0

I've been seeing an occasional crash in my Crashlytics logs that I haven't been able to replicate myself. I've searched everywhere and thought I had followed the same guidelines shown everywhere on how to handle creating and dismissing dialogs around an AsyncTask, namely, create and display them from onPreExecute() and dismiss them in onPostExecute(). Am I missing something here?

Here's the complete code for the class:

public class MyActivity extends BaseActivity implements AsyncResponse {


    private AlertDialog mAlert;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        populateData();
    }

    public void processFinish(boolean result){
        if(result) {
            //setup and start new intent
            finish();
        }
        else{
            AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
            //setup alert
            mAlert = builder.create();
            mAlert.show();
        }
    }

    private void populateData() {
        boolean hasConnection = Utility.isNetworkAvailable(this);
        if(!hasConnection){
            showConnectDialog();
        }
        MyTask myTask = new MyTask(this);
        myTask.delegate = this;
        myTask.execute();
    }

    @Override
    protected void onPause(){
        super.onPause();
        if ( mAlert!=null && mAlert.isShowing() ){
            mAlert.cancel();
        }
    }

    private static ProgressDialog mProgressDialog;
    private static void showProgressDialog(Context context) {

        if (mProgressDialog == null) {
            //setup dialog
        }

        if (! ((Activity) context).isFinishing()) {
            mProgressDialog.show();
        }
    }

    private static void dismissProgressDialog() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.dismiss();
        }
    }

    @Override
    protected void onDestroy() {
        dismissProgressDialog();
        super.onDestroy();
    }

    private static class MyTask extends AsyncTask<Void, Void, Boolean> {

        final WeakReference<BaseActivity> activityRef;

        private AsyncResponse delegate=null;

        private PowerManager.WakeLock mWakeLock;


        private MyTask(BaseActivity activity) {
            activityRef = new WeakReference<>(activity);
        }

        @Override
        protected void onPreExecute() {
            // take CPU lock to prevent CPU from going off if the user
            // presses the power button during download
            Context context = activityRef.get();
            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
            mWakeLock.acquire(90000); //1.5 minute timeout

            int currentOrientation = context.getResources().getConfiguration().orientation;
            if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
                ((Activity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                ((Activity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
            showProgressDialog(context);
        }

        @Override
        protected void onPostExecute(Boolean result) {
            mWakeLock.release();
            dismissProgressDialog();
            BaseActivity activity = activityRef.get();
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
            delegate.processFinish(result);
        }



        @Override
        protected Boolean doInBackground(Void... params) {
            DataRetriever retriever = new DataRetriever(activityRef.get());
            return retriever.getData();
        }
    }

}

The exception log shows: Caused by android.view.WindowManager$BadTokenException Unable to add window -- token android.os.BinderProxy@a60eb7a0 is not valid; is your activity running?

android.view.ViewRootImpl.setView (ViewRootImpl.java:559)
android.view.WindowManagerGlobal.addView (WindowManagerGlobal.java:269)
android.view.WindowManagerImpl.addView (WindowManagerImpl.java:69)
android.app.Dialog.show (Dialog.java:281)
com.xxx.MyActivity.showProgressDialog (MyActivity.java:1100)
com.xxx.MyActivity$MyTask.onPreExecute (MyActivity.java:95)
android.os.AsyncTask.executeOnExecutor (AsyncTask.java:586)
android.os.AsyncTask.execute (AsyncTask.java:534)
com.xxx.MyActivity.populateLanguages (LanguagePopulateActivity.java:32)
com.xxx.MyActivity.onCreate (LanguagePopulateActivity.java:9)

Thanks!

asorenson
  • 159
  • 1
  • 14
  • Thanks @ADM, that may have solved it, though I probably won't know for awhile, as I haven't been able to replicate it. It seems that it is not sufficient to check that the dialog is not null, and that the dialog isShowing(), but that checking if the Activity isFinishing() is the key. – asorenson Jul 31 '18 at 16:56
  • @asorenson I notice in the code you posted that you are checking `isFinishing` ; I've had a similar issue while doing a similar check and believe there is still cases where this check is insufficient. I wonder if using the `onStop` to set a similar flag might cover all cases. Btw, the 'Back' button seems to be one way to bring this about provided the timing is right. – Andy Jul 31 '18 at 17:06
  • @Andy Yes, I used the isFinishing() to check before displaying it, but then didn't check that before dismissing it, which is where I've seen my crashes. I'm going to try to wrap everything in the onPostExecute in an if( ! activity.isFinishing()) block. Though, I'm concerned about the wakeLock.release() - if the activity has closed, I don't want to be holding on to a wakeLock I then can't release. – asorenson Jul 31 '18 at 17:16

0 Answers0