Xamarin Native equivalent of Xamarin.Forms App OnSleep and OnResume - xamarin

I'm working with a Xamarin Native application, and would like to perform some logic when the application is focused / out of focused in android - similar to Xamarin.Forms Application.OnSleep(), and Application.OnResume() (not to be confused with Activity.OnResume, and Activity.OnPause)
Just wondering what solution others have used to solve this scenario (besides migrating to Xamarin.Forms).

when the application is focused / out of focused in android
Do you mean you want to listener the application is running in foreground or background ?
If yes,you could use IActivityLifecycleCallbacks to listen the status.
Application registration ActivityLifecycleCallbacks, such, when each activity in the app lifecycle occurs, the Application can be listening to. The number of public void onActivityStarted(activity activity) and public void onActivityStopped(activity activity) of an activity can be used to determine whether the app is in the foreground. Because when the app is in the foreground, an activity must have started onActivityStarted but not onActivityStopped, so the statistics of the number of activities opened in the app must be 1. When the app switches to the background, activityStartCount will be 0.
so write a Helper classes :
public class AppFrontBackHelper
{
public static OnAppStatusListener mOnAppStatusListener;
private LifecycleCallBack lifecycleCallBack;
public AppFrontBackHelper()
{
}
/**
* Register status listener, only used in Application
* #param application
* #param listener
*/
public void register(Application application, OnAppStatusListener listener)
{
mOnAppStatusListener = listener;
lifecycleCallBack = new LifecycleCallBack();
application.RegisterActivityLifecycleCallbacks(lifecycleCallBack);
}
public void unRegister(Application application) => application.UnregisterActivityLifecycleCallbacks(lifecycleCallBack);
public interface OnAppStatusListener
{
void onFront();
void onBack();
}
public class LifecycleCallBack : Java.Lang.Object, Application.IActivityLifecycleCallbacks
{
public int activityStartCount { get; private set; }
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
activityStartCount++;
//A value from 1 to 0 indicates cutting from the background to the foreground
if (activityStartCount == 1)
{
if (mOnAppStatusListener != null)
{
mOnAppStatusListener.onFront();
}
}
}
public void OnActivityStopped(Activity activity)
{
activityStartCount--;
//A value from 1 to 0 indicates cutting from the foreground to the background
if (activityStartCount == 0)
{
//from foreground to background
if (mOnAppStatusListener != null)
{
mOnAppStatusListener.onBack();
}
}
}
}
}
then custom an Application and regist the listener :
[Application]
public class MyApplication : Application,AppFrontBackHelper.OnAppStatusListener
{
protected MyApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnCreate()
{
base.OnCreate();
AppFrontBackHelper appFrontBackHelper = new AppFrontBackHelper();
appFrontBackHelper.register(this, this);
}
public void onBack()
{
Toast.MakeText(this, "from front to back", ToastLength.Short).Show();
}
public void onFront()
{
Toast.MakeText(this, "from back to front", ToastLength.Short).Show();
}
}

[Application]
public class MyApp : Application, ILifecycleObserver
{
[Export, Lifecycle.Event.OnStop]
public void OnAppBackgrounded()
{
}
[Export, Lifecycle.Event.OnStart]
public void OnAppForegrounded()
{
}
public override void OnCreate()
{
// For handling when the app goes into the foreground or background
ProcessLifecycleOwner.Get().Lifecycle.AddObserver(this);
}
So far it appears to work as expected. ProcessLifecycleOwner is in the Xamarin.Android.Arch.Lifecycle.Extensions nuget package.

Related

How to implement Local Push notification in Xamarin Android

I am having the Xamarin.Forms application. I want to implement the local push notification for Android platform, through which an application can receive the notification whenever the app is minimized or phone is locked. I also want to wake-up the phone and display the notification on the lock screen whenever the phone is locked.
As I am new in this kindly help me.
Thanks in advance.
Vivek
I think you should consider two things.
1.Listen for the screen lock:
create a ScreenListener.cs :
public class ScreenListener
{
private Context mContext;
private ScreenBroadcastReceiver mScreenReceiver;
private static ScreenStateListener mScreenStateListener;
public ScreenListener(Context context)
{
mContext = context;
mScreenReceiver = new ScreenBroadcastReceiver();
}
/**
* screen BroadcastReceiver
*/
private class ScreenBroadcastReceiver : BroadcastReceiver
{
private String action = null;
public override void OnReceive(Context context, Intent intent)
{
action = intent.Action;
if (Intent.ActionScreenOn == action)
{ // screen on
mScreenStateListener.onScreenOn();
}
else if (Intent.ActionScreenOff == action)
{ // screen off
mScreenStateListener.onScreenOff();
}
else if (Intent.ActionUserPresent == action)
{ // unlock
mScreenStateListener.onUserPresent();
}
}
}
/**
* begin to listen screen state
*
* #param listener
*/
public void begin(ScreenStateListener listener)
{
mScreenStateListener = listener;
registerListener();
getScreenState();
}
/**
* get screen state
*/
private void getScreenState()
{
PowerManager manager = (PowerManager)mContext
.GetSystemService(Context.PowerService);
if (manager.IsScreenOn)
{
if (mScreenStateListener != null)
{
mScreenStateListener.onScreenOn();
}
}
else
{
if (mScreenStateListener != null)
{
mScreenStateListener.onScreenOff();
}
}
}
/**
* stop listen screen state
*/
public void unregisterListener()
{
mContext.UnregisterReceiver(mScreenReceiver);
}
/**
* regist screen state broadcast
*/
private void registerListener()
{
IntentFilter filter = new IntentFilter();
filter.AddAction(Intent.ActionScreenOn);
filter.AddAction(Intent.ActionScreenOff);
filter.AddAction(Intent.ActionUserPresent);
mContext.RegisterReceiver(mScreenReceiver, filter);
}
public interface ScreenStateListener
{// Returns screen status information to the caller
void onScreenOn();
void onScreenOff();
void onUserPresent();
}
}
then in the MainActivity.cs:
public class MainActivity : AppCompatActivity,ScreenStateListener
{
ScreenListener mScreenListener;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
mScreenListener = new ScreenListener(this);
}
protected override void OnDestroy()
{
base.OnDestroy();
mScreenListener.unregisterListener();
}
protected override void OnResume()
{
base.OnResume();
mScreenListener.begin(this);
}
public void onScreenOn()
{
Console.WriteLine("onScreenOn");
}
public void onScreenOff()
{
Console.WriteLine("onScreenOff");
}
public void onUserPresent()
{
Console.WriteLine("onUserPresent");
}
}
2.creat loacal Notification:
finally you just push the notification in the onScreenOff() method.
What you need is push notifications not local notifications. Local notifications only work if your app is running. Push notifications are handled by OS (Android in this case). Xamarin is recommending using Firebase service to handle it. Procedure is pretty straight forward all what you have to do is follow Tutorial from official Xamarin site.
Remote Notifications with Firebase Cloud Messaging

How to migrate MVVMCross based Xamarin.android project into Intune managed one

I have a android project running smoothly, it uses MVVMCross at its core.
The problem came when I was asked manage the app protection policies with Intune.
Now Intune is forcing me to use their managed activity and all other managed namespaces provided by Intune SDK.
In that case, how I can proceed with it?
I tried changing activities base class to Intune's one, in hope to use general things provided by Mvvmcross, such as IOC, dependency injections.
I customised App startup as Intune wants that means there will not be any setup/app.cs class calls involvement.
So I launch Splash activity -> and it launches MainActivity, in MainActivity I am manually injecting all the Dependencies which I require.
Because all these syntaxes are throwing exception under Intune managed activities
example: Mvx.RegisterType<IDeviceInformation, DeviceInformation>();
Above throws exception.
How do I proceed with this migration keeping MVVMcross basic functionality intact?
There is a couple of solutions to that matter that I can think of.
If you only need the DI you can add another DI manager package and handle it from there which will be simpler than configuring Mvx to do that only.
If you need other capabilities of Mvx then you will have to do what Mvx does in its base classes and implement them taking into consideration setting the appropiate interfaces to your base classes.
In Android, in order to get the Setup and Activities working you'll have to:
Register your setup in your android Application file as done here
this.RegisterSetupType<TMvxAndroidSetup>();
Implement your own base activity that takes into consideration the implementation of IMvxEventSourceActivity such as here and also the MvxActivity like here in order to have the events and the data context / viewmodel handling
[Register("mvvmcross.platforms.android.views.base.MvxEventSourceActivity")]
public abstract class MvxEventSourceActivity
: Activity, IMvxEventSourceActivity
{
protected MvxEventSourceActivity()
{
}
protected MvxEventSourceActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected override void OnCreate(Bundle bundle)
{
CreateWillBeCalled.Raise(this, bundle);
base.OnCreate(bundle);
CreateCalled.Raise(this, bundle);
}
protected override void OnDestroy()
{
DestroyCalled.Raise(this);
base.OnDestroy();
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
NewIntentCalled.Raise(this, intent);
}
protected override void OnResume()
{
base.OnResume();
ResumeCalled.Raise(this);
}
protected override void OnPause()
{
PauseCalled.Raise(this);
base.OnPause();
}
protected override void OnStart()
{
base.OnStart();
StartCalled.Raise(this);
}
protected override void OnRestart()
{
base.OnRestart();
RestartCalled.Raise(this);
}
protected override void OnStop()
{
StopCalled.Raise(this);
base.OnStop();
}
public override void StartActivityForResult(Intent intent, int requestCode)
{
StartActivityForResultCalled.Raise(this, new MvxStartActivityForResultParameters(intent, requestCode));
base.StartActivityForResult(intent, requestCode);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
ActivityResultCalled.Raise(this, new MvxActivityResultParameters(requestCode, resultCode, data));
base.OnActivityResult(requestCode, resultCode, data);
}
protected override void OnSaveInstanceState(Bundle outState)
{
SaveInstanceStateCalled.Raise(this, outState);
base.OnSaveInstanceState(outState);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
DisposeCalled.Raise(this);
}
base.Dispose(disposing);
}
public event EventHandler DisposeCalled;
public event EventHandler<MvxValueEventArgs<Bundle>> CreateWillBeCalled;
public event EventHandler<MvxValueEventArgs<Bundle>> CreateCalled;
public event EventHandler DestroyCalled;
public event EventHandler<MvxValueEventArgs<Intent>> NewIntentCalled;
public event EventHandler ResumeCalled;
public event EventHandler PauseCalled;
public event EventHandler StartCalled;
public event EventHandler RestartCalled;
public event EventHandler StopCalled;
public event EventHandler<MvxValueEventArgs<Bundle>> SaveInstanceStateCalled;
public event EventHandler<MvxValueEventArgs<MvxStartActivityForResultParameters>> StartActivityForResultCalled;
public event EventHandler<MvxValueEventArgs<MvxActivityResultParameters>> ActivityResultCalled;
}
[Register("mvvmcross.platforms.android.views.MvxActivity")]
public abstract class MvxActivity
: MvxEventSourceActivity
, IMvxAndroidView
{
protected View _view;
protected MvxActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected MvxActivity()
{
BindingContext = new MvxAndroidBindingContext(this, this);
this.AddEventListeners();
}
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
public IMvxViewModel ViewModel
{
get
{
return DataContext as IMvxViewModel;
}
set
{
DataContext = value;
OnViewModelSet();
}
}
public void MvxInternalStartActivityForResult(Intent intent, int requestCode)
{
StartActivityForResult(intent, requestCode);
}
public IMvxBindingContext BindingContext { get; set; }
public override void SetContentView(int layoutResId)
{
_view = this.BindingInflate(layoutResId, null);
SetContentView(_view);
}
protected virtual void OnViewModelSet()
{
}
protected override void AttachBaseContext(Context #base)
{
if (this is IMvxSetupMonitor)
{
// Do not attach our inflater to splash screens.
base.AttachBaseContext(#base);
return;
}
base.AttachBaseContext(MvxContextWrapper.Wrap(#base, this));
}
private readonly List<WeakReference<Fragment>> _fragList = new List<WeakReference<Fragment>>();
public override void OnAttachFragment(Fragment fragment)
{
base.OnAttachFragment(fragment);
_fragList.Add(new WeakReference<Fragment>(fragment));
}
public List<Fragment> Fragments
{
get
{
var fragments = new List<Fragment>();
foreach (var weakReference in _fragList)
{
if (weakReference.TryGetTarget(out Fragment f))
{
if (f.IsVisible)
fragments.Add(f);
}
}
return fragments;
}
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
ViewModel?.ViewCreated();
}
protected override void OnDestroy()
{
base.OnDestroy();
ViewModel?.ViewDestroy(IsFinishing);
}
protected override void OnStart()
{
base.OnStart();
ViewModel?.ViewAppearing();
}
protected override void OnResume()
{
base.OnResume();
ViewModel?.ViewAppeared();
}
protected override void OnPause()
{
base.OnPause();
ViewModel?.ViewDisappearing();
}
protected override void OnStop()
{
base.OnStop();
ViewModel?.ViewDisappeared();
}
}
public abstract class MvxActivity<TViewModel>
: MvxActivity
, IMvxAndroidView<TViewModel> where TViewModel : class, IMvxViewModel
{
public new TViewModel ViewModel
{
get { return (TViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
}
Also you'll have to implement your own splash activity like here which implements the IMvxSetupMonitor and is the one who ends up calling the setup here by calling MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext); and initializing a monitor.
[Register("mvvmcross.platforms.android.views.MvxSplashScreenActivity")]
public abstract class MvxSplashScreenActivity
: MvxActivity, IMvxSetupMonitor
{
protected const int NoContent = 0;
private readonly int _resourceId;
private Bundle _bundle;
public new MvxNullViewModel ViewModel
{
get { return base.ViewModel as MvxNullViewModel; }
set { base.ViewModel = value; }
}
protected MvxSplashScreenActivity(int resourceId = NoContent)
{
RegisterSetup();
_resourceId = resourceId;
}
protected MvxSplashScreenActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected virtual void RequestWindowFeatures()
{
RequestWindowFeature(WindowFeatures.NoTitle);
}
protected override void OnCreate(Bundle bundle)
{
RequestWindowFeatures();
_bundle = bundle;
var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext);
setup.InitializeAndMonitor(this);
base.OnCreate(bundle);
if (_resourceId != NoContent)
{
// Set our view from the "splash" layout resource
// Be careful to use non-binding inflation
var content = LayoutInflater.Inflate(_resourceId, null);
SetContentView(content);
}
}
private bool _isResumed;
protected override void OnResume()
{
base.OnResume();
_isResumed = true;
var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext);
setup.InitializeAndMonitor(this);
}
protected override void OnPause()
{
_isResumed = false;
var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext);
setup.CancelMonitor(this);
base.OnPause();
}
public virtual async Task InitializationComplete()
{
if (!_isResumed)
return;
await RunAppStartAsync(_bundle);
}
protected virtual async Task RunAppStartAsync(Bundle bundle)
{
if (Mvx.IoCProvider.TryResolve(out IMvxAppStart startup))
{
if(!startup.IsStarted)
{
await startup.StartAsync(GetAppStartHint(bundle));
}
else
{
Finish();
}
}
}
protected virtual object GetAppStartHint(object hint = null)
{
return hint;
}
protected virtual void RegisterSetup()
{
}
}
public abstract class MvxSplashScreenActivity<TMvxAndroidSetup, TApplication> : MvxSplashScreenActivity
where TMvxAndroidSetup : MvxAndroidSetup<TApplication>, new()
where TApplication : class, IMvxApplication, new()
{
protected MvxSplashScreenActivity(int resourceId = NoContent) : base(resourceId)
{
}
protected override void RegisterSetup()
{
this.RegisterSetupType<TMvxAndroidSetup>();
}
}
This will cover the basics I think.
Hope it helps you to get you to the right direction

Is it possible to Fetch user location from a Worker class?

I have to schedule a work to fetch user current location and update to server in a given interval (Even the app is not running).
I am trying to WorkManagerAPI to implement the functionality.
Is it possible to fetch the current location of the user from the doWork() method ?
locationManager.requestLocationUpdates(
provider, timeInterval, travelDistance, locationListener
);
When I request Location updates from the doWork() it throws below error.
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
As per my understanding, when implementing LocationManager.requestLocationUpdates() on a Worker thread, the call is being made on a non-UI, background thread created by WorkManager. LocationManager.requestLocationUpdates() is an asynchronous call possibly on another background thread. To handle the callbacks defined by the LocationListener, the calling thread must stay alive. Thats why the exception says,
Can't create handler inside thread that has not called Looper.prepare()
Check the code snippet below. Please consider this as pseudocode, I haven't tested this piece of code.
public class LocationWorker extends Worker {
String LOG_TAG = "LocationWorker";
private Context mContext;
private MyHandlerThread mHandlerThread;
public LocationWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
mContext = context;
}
#NonNull
#Override
public Result doWork() {
Log.d(LOG_TAG, "doWork");
mHandlerThread = new MyHandlerThread("MY_THREAD");
mHandlerThread.start();
Runnable runnable = new Runnable() {
#Override
public void run() {
LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
String bestProvider = locationManager.getBestProvider(new Criteria(), true);
boolean permission = false;
if (PermissionChecker.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
PermissionChecker.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Log.e(LOG_TAG, "This app requires ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions.");
permission = true;
}
Log.d(LOG_TAG, "permission: "+permission);
Log.d(LOG_TAG, "bestProvider: "+bestProvider);
if (permission && bestProvider != null) {
MyLocationListener locListener = new MyLocationListener();
locationManager.requestLocationUpdates(bestProvider, 500, 1, locListener, mHandlerThread.getLooper());
}
}
};
mHandlerThread.post(runnable);
return Result.success();
}
class MyHandlerThread extends HandlerThread {
Handler mHandler;
MyHandlerThread(String name) {
super(name);
}
#Override
protected void onLooperPrepared() {
Looper looper = getLooper();
if (looper != null)
mHandler = new Handler(looper);
}
void post(Runnable runnable) {
if (mHandler != null)
mHandler.post(runnable);
}
}
class MyLocationListener implements LocationListener
{
#Override
public void onLocationChanged(final Location loc)
{
Log.d(LOG_TAG, "Location changed: " + loc.getLatitude() +","+ loc.getLongitude());
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
Log.d(LOG_TAG, "onStatusChanged");
}
#Override
public void onProviderDisabled(String provider)
{
Log.d(LOG_TAG, "onProviderDisabled");
}
#Override
public void onProviderEnabled(String provider)
{
Log.d(LOG_TAG, "onProviderEnabled");
}
}
}

Xamarin support for AdMob Rewarded Interstitial

Today I noticed AdMob is offering rewarded interstitial option. I'd like to integrate it in my game. Does the current Xamarin.GooglePlayServices.Ads support the integration?
Has anyone tried it? Love to hear from your experience.
Thanks!
I have just attempted to integrate them and they work fine for me in debug (yet to try in release mode - will update once I've tried it)
Simply create an interstitial ad as you normally would but use the Reward Video ad unit ID instead of the usual interstitial ad ID.
If you want to try it yourself, the sample Reward Video ad unit ID provided by Google for testing is:
ca-app-pub-3940256099942544/5224354917
#region RewardedViewAd
private IRewardedVideoAd rewardedVideoAd;
private void InitialRewardVideo()
{
rewardedVideoAd = MobileAds.GetRewardedVideoAdInstance(this);
rewardedVideoAd.RewardedVideoAdListener = this;
this.LoadRewardAd();
}
private void LoadRewardAd()
{
if (!rewardedVideoAd.IsLoaded)
{
#if DEBUG
rewardedVideoAd.LoadAd(" ca-app-pub-3940256099942544/5224354917", new AdRequest.Builder().Build());
#else
rewardedVideoAd.LoadAd("ca-app-pub-9045308343519031/327467645", new AdRequest.Builder().Build());
#endif
}
}
private void StartRewardedVideoAd()
{
if (rewardedVideoAd.IsLoaded)
{
rewardedVideoAd.Show();
}
}
public void OnRewarded(IRewardItem reward)
{
var coins = reward.Amount;
}
public void OnRewardedVideoAdClosed()
{
this.LoadRewardAd();
}
public void OnRewardedVideoAdFailedToLoad(int errorCode)
{
}
public void OnRewardedVideoAdLeftApplication()
{
}
public void OnRewardedVideoAdLoaded()
{
}
public void OnRewardedVideoAdOpened()
{
}
public void OnRewardedVideoCompleted()
{
}
public void OnRewardedVideoStarted()
{
}
protected override void OnPause()
{
this.rewardedVideoAd.Pause(this);
base.OnPause();
}
protected override void OnResume()
{
this.rewardedVideoAd.Resume(this);
base.OnResume();
}
protected override void OnDestroy()
{
this.rewardedVideoAd.Destroy(this);
base.OnDestroy();
}
#endregion;

Fatal Exception: java.lang.IllegalArgumentException occurs from ProgressDialog

I've 10 apps which uses AsyncTasks. As you know i show progressdialog in asynctasks to show progress of the task. But there is a problem that i couldn't solve so far about progressdialog.
Here is one of my AsyncTask class (which is not in a other class);
public class GetBalanceAsyncTask extends AsyncTask<Void, Void, String> {
Context context;
ProgressDialog pd;
public GetBakiyeAsyncTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... arg0) {
String userAgent = HttpHelper.getRandomUserAgent(context);
return HttpHelper.post(PreferenceHelper.getBalanceQueryAPI(context), userAgent);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = ProgressDialog.show(context, "","Please wait...",true);
}
#Override
protected void onPostExecute(String result) {
try {
if (pd != null & pd.isShowing()) {
pd.dismiss();
pd = null;
}
} catch (IllegalArgumentException e) {
pd = null;
e.printStackTrace();
}
if (result != null & result.length() > 0) {
Utils.doTask(result);
} else {
Utils.ShowToast(context,
"An error has occurred, please try again.",
STYLE_CONFIRM, LENGTH_LONG);
}
super.onPostExecute(result);
}
}
and the execption is
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:381)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:226)
at android.view.Window$LocalWindowManager.removeView(Window.java:432)
at android.app.Dialog.dismissDialog(Dialog.java:278)
at android.app.Dialog.access$000(Dialog.java:71)
at android.app.Dialog$1.run(Dialog.java:111)
at android.app.Dialog.dismiss(Dialog.java:268)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:27)
at fragments.RuyalarFragment$getRuyalarAsyncTask.onPostExecute(GetBalanceAsyncTask.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(NativeStart.java)
I've searched the solution almost everywhere but there is no working results. Most of answers contain use isFinishing, onDestroy or something like this but no body is sure which is working.
Thanks for advice.
How to reproduce the bug:
Enable this option on your device: Settings -> Developer Options -> Don't keep Activities.
Press Home button while the 'AsyncTask' is executing and the ProgressDialog is showing.
The Android OS will destroy an activity as soon as it is hidden. When onPostExecute is called the Activity will be in "finishing" state and the ProgressDialog will be not attached to Activity.
How to fix it:
Check for the activity state in your onPostExecute method.
Dismiss the ProgressDialog in onDestroy method. Otherwise, android.view.WindowLeaked exception will be thrown. This exception usually comes from dialogs that are still active when the activity is finishing.
try this code :
public class YourActivity extends Activity {
<...>
private void showProgressDialog() {
if (pDialog == null) {
pDialog = new ProgressDialog(StartActivity.this);
pDialog.setMessage("Loading. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
}
pDialog.show();
}
private void dismissProgressDialog() {
if (pDialog != null && pDialog.isShowing()) {
pDialog.dismiss();
}
}
#Override
protected void onDestroy() {
dismissProgressDialog();
super.onDestroy();
}
class LoadAllProducts extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
showProgressDialog();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args)
{
doMoreStuff("internet");
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url)
{
if (YourActivity.this.isDestroyed()) {
return;
}
dismissProgressDialog();
something(note);
}
}
}
Late to the party, but really this question has many duplicates on SO.
The most comprehensive summary of solutions I've found is here.
Basically use a retained Fragment to connect your AsyncTask to the new Activity.

Resources