0

I have an activity that is displayed in portrait only and in my tablet it causes the following:

 android.view.WindowLeaked: Activity com.spicycurryman.getdisciplined10.app.InstalledAppActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{53210b88 V.E..... R.....ID 0,0-1520,192} that was originally added here
            at android.view.ViewRootImpl.<init>(ViewRootImpl.java:354)
            at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:216)
            at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
            at android.app.Dialog.show(Dialog.java:281)
            at com.spicycurryman.getdisciplined10.app.InstalledAppActivity$LoadApplications.onPreExecute(InstalledAppActivity.java:306)
            at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
            at android.os.AsyncTask.execute(AsyncTask.java:534)
            at com.spicycurryman.getdisciplined10.app.InstalledAppActivity.onCreate(InstalledAppActivity.java:105)
            at android.app.Activity.performCreate(Activity.java:5104)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5041)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)

I am using an AsyncTask to load a listview of installed apps on the phone and using a progressdialog.

I have researched this problem:

Progress dialog and AsyncTask error

android.view.WindowLeaked exception

Android Error: Window Leaked in AsyncTask

I was able to produce this code so that the whole app doesn't crash and burn, but the exception is still thrown and the activity screen is kind of shaky after the button click and the whole transition is not really smooth.

 @Override
        protected void onPostExecute(Void result) {

            apkList.setAdapter(new ApkAdapter(InstalledAppActivity.this, packageList1, packageManager));

            try {
                if ((this.pDialog != null) && this.pDialog.isShowing()) {
                    this.pDialog.dismiss();
                }
            } catch (final IllegalArgumentException e) {
                // Handle or log or ignore
            } catch (final Exception e) {
                // Handle or log or ignore
            } finally {
                this.pDialog = null;
            }


            super.onPostExecute(result);
        }

Dismissing the progress dialog or calling finish() doesn't really solve the problem either...

How would I fix this?

Here is most of the AsyncTask code:

    private class LoadApplications extends AsyncTask<Void, Void, Void> {


        private ProgressDialog pDialog;
        List<PackageInfo> packageList1 = new ArrayList<PackageInfo>();

        public LoadApplications(Context context){
            Context mContext = context;
        }

        @Override
        protected Void doInBackground(Void... params) {

            List<PackageInfo> packageList = packageManager
                    .getInstalledPackages(PackageManager.GET_PERMISSIONS);

            List<PackageInfo> packageList2 = packageManager
                    .getInstalledPackages(PackageManager.GET_PERMISSIONS);

            for(PackageInfo pi : packageList) {

                boolean b = isSystemPackage(pi);
                boolean c = isSystemPackage1(pi);
                boolean d = isSystemPackage2(pi);


                if ((!b || !c ) && d ){
                    packageList1.add(pi);
                }

            }

            //here you got email and message apps in the 

            for(PackageInfo pi : packageList) {

                boolean b = isSystemPackage3(pi);
                boolean c = isSystemPackage4(pi);


                if (b || c){
                    packageList1.add(pi);
                }

            }






            //sort by application name

            final PackageItemInfo.DisplayNameComparator comparator = new PackageItemInfo.DisplayNameComparator(packageManager);

            Collections.sort(packageList1, new Comparator<PackageInfo>() {
                @Override
                public int compare(PackageInfo lhs, PackageInfo rhs) {
                    return comparator.compare(lhs.applicationInfo, rhs.applicationInfo);
                }
            });

            return null;
        }
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }

        @Override
        protected void onPreExecute() {
            pDialog = new ProgressDialog(InstalledAppActivity.this);
            pDialog.setMessage("Loading your apps...");
            pDialog.show();

        }
        //Inefficient patch to prevent Window Manager error


        @Override
        protected void onPostExecute(Void result) {

            apkList.setAdapter(new ApkAdapter(InstalledAppActivity.this, packageList1, packageManager));

            try {
                if ((this.pDialog != null) && this.pDialog.isShowing()) {
                    this.pDialog.dismiss();
                }
            } catch (final IllegalArgumentException e) {
                // Handle or log or ignore
            } catch (final Exception e) {
                // Handle or log or ignore
            } finally {
                this.pDialog = null;
            }


            super.onPostExecute(result);
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
    }
}
Community
  • 1
  • 1
Rohit Tigga
  • 2,373
  • 9
  • 43
  • 81
  • I think on `Orientation` change your `Activity` is restarting so `AsyncTast` is called again. – Rustam Sep 18 '14 at 18:46

2 Answers2

0

try this :

@Override
    public Object onRetainNonConfigurationInstance() {
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog = null;
        }
        if (asynTask!= null) {
            asynTask.detach();
        }
        return ayncTask;
    }
Rustam
  • 6,485
  • 1
  • 25
  • 25
0

Declaring a non-static inner AsyncTask in your activity is not a good idea because it holds a reference to the activity and this could be a couse of the leak. However, various configuration changes could cause the OS to destroy and recreate the activity. There are a number of solutions and Rustam's anser is an example.

However, I prefer to user either AsyncTaskLoader or use some sort of asynchronous callback, like a broadcast. The asynchronous callback decouples your AsyncTask from the Activity.

dhaag23
  • 6,106
  • 37
  • 35