0

I have an AsyncTask in my project and there is an alert which says:

This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask) less... (Ctrl+F1) A static field will leak contexts. Non-static inner classes have an implicit reference to their outer class. If that outer class is for example a Fragment or Activity, then this reference means that the long-running handler/loader/task will hold a reference to the activity which prevents it from getting garbage collected. Similarly, direct field references to activities and fragments from these longer running instances can cause leaks. ViewModel classes should never point to Views or non-application Contexts.

here is my code that is contain this alert :

ProgressDialog progressDialog;
     AsyncTask<String,Void,Boolean> asyncTask = new AsyncTask<String, Void, Boolean>() {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog.setTitle("بارگذاری");
            progressDialog.setMessage("در حال دریافت اطلاعات از پایگاه داده..");
            progressDialog.setCancelable(false);
            progressDialog.show();
        }


        @Override
        protected Boolean doInBackground(String... strings) {
            Cursor cursor = DataBase.getinfos(page,limit);

            if (cursor.isAfterLast()){
                return false;
            }else {

                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    PropertyInfo propertyInfo = new PropertyInfo();
                    propertyInfo.setId(cursor.getInt(0));
                    propertyInfo.setAddress(cursor.getString(1));
                    propertyInfo.setDetails(cursor.getString(2));
                    propertyInfo.setOptions(cursor.getString(3));
                    propertyInfo.setMortgage_cost(cursor.getLong(4));
                    propertyInfo.setRent_cost(cursor.getLong(5));
                    propertyInfo.setOwner_name(cursor.getString(6));
                    propertyInfo.setUnits_per_floor(cursor.getInt(7));
                    propertyInfo.setCurrent_floor(cursor.getInt(8));
                    propertyInfo.setFloors_count(cursor.getInt(9));
                    propertyInfo.setRoom_count(cursor.getString(10));
                    propertyInfo.setOwner_phone(cursor.getString(11));
                    propertyInfo.setDocument_type(cursor.getString(12));
                    propertyInfo.setRequest_type(cursor.getString(13));
                    propertyInfo.setProperty_type(cursor.getString(14));
                    propertyInfo.setCost(cursor.getLong(15));
                    propertyInfo.setArea(cursor.getInt(16));
                    propertyInfo.setHouse_type(cursor.getString(17));
                    propertyInfo.setLocation(cursor.getString(19));
                    propertyInfo.setNoeMorajeKonande(cursor.getString(18));
                    propertyInfo.setShomareSafhe(cursor.getString(20));
                    propertyInfo.setDate(cursor.getString(21));
                    arrayList.add(propertyInfo);
                    lastRecivedDataSize++;
                }
                return true;
            }
        }


        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            loading = aBoolean;
            if (arrayList.isEmpty()) {
                setContentView(R.layout.no_result);
            } else {
                mAdapter = new RecyclerInfoAdapter(arrayList, ShowAllDataActivity.this);
                mAdapter.notifyDataSetChanged();
                recyclerView.setAdapter(mAdapter);
                recyclerView.scrollToPosition(pastVisiblesItems + visibleItemCount - 1);
                page++;


            }
            progressDialog.dismiss();

        }
    };

    asyncTask.execute();

anybody knows the problem ??

  • Is this referenced from an activity or view? – J E Carter II Feb 04 '19 at 20:04
  • @JECarterII it is in an activity – Mohammad Seyedmahmudi Feb 04 '19 at 20:20
  • Take a look at this list of memory leak fixes I found. https://android.jlelse.eu/9-ways-to-avoid-memory-leaks-in-android-b6d81648e35e There seems to be a general caution about async activities continuing to run once the activity is destroyed. Making it static is one fix, listed towards the bottom of that article. – J E Carter II Feb 04 '19 at 20:38
  • Possible duplicate of [Warning: This AsyncTask class should be static or leaks might occur](https://stackoverflow.com/questions/44309241/warning-this-asynctask-class-should-be-static-or-leaks-might-occur) – Aashish Kumar May 25 '19 at 08:51

2 Answers2

1

Just to clarify what ynsmtki means in your specific case: Your asyncTask is declared within the UI event-handler / callback method (lets name it onSomeUIEventHandler{}, but it shall spawn its own thread carrying with it longer scope references such as (1) progressDialog, (2) DataBase, (3) propertyInfo, which are the source of the leak warnings.

As others have pointed out this has always been a quiet problem until IntelliJ deployed (unleashed, actually) their KotlinT analyser two years back. It has been a puzzle to resolve until recently (in AS v3.0+) where the analyser actually provides meaningful hints at resolving the leak. Here's what it now assists with and it even generates the subclass signatures for you through the IDE:

So you need to execute() that async task thread with read-only copies of the above three by specifying getter() methods for them, namely getDatabase(), getProgressDialog() and getPropertyInfo() which you use in the extended asyncTask class thus:

static class HandleDBaseAsyncTask extends AsyncTask<Parameterized.Parameters,Process, Result>{
final PropertyInfo propertyInfo = getPropertyInfo();
final YourDatabaseClass Database = getDatabase();
final ProgressDialog progressDialog = getProgressDialog();
// Then finish off with your original
onPreExecute() {...}
doInBackground(){...}
onPostExecute(){...}
}

Then back in the original callback for the Dialog leaker:

ProgressDialog progressDialog;
ProgressDialog getProgressDialog(){ return progressDialog;}
// and the same for other leakers

onSomeUIEventHandler{
HandleDBaseAsyncTask handleDBTask = new HandleDBaseAsyncTask();
handleDBTask.execute();
// ...
}

There may be other subtleties to take care of where instance methods of the getters cannot be invoked in the task's static context, so you would make them static or pass in their singleton container (like Activity or Context) into your asyncTask block to use their getters() there to get past the compiler error.

ParentContainer parent = getDialogContainer();
final ProgressDialog progressDialog = parent.getProgressDialog() // etc
MKhomo
  • 179
  • 1
  • 10
0

Create a separate class that implements AsyncTask, then in your activity instantiate it, and run the execute method.

ynsmtkl
  • 105
  • 3
  • 10