androidmemory-leaksasynctaskloader

This Loader class should be static or leaks might occur | Inner class memory leak | AsyncTaskLoader memory leak -


I am receiving the following warning around AsyncTaskLoader in android studio:

"This Loader class should be static or leaks might occur (anonymous android.support.v4.content.AsyncTaskLoader) 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 the code snippet from my application:

@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs) {

    return new AsyncTaskLoader<Cursor>(this) {

        // Initialize a Cursor, this will hold all the task data
        Cursor mTaskData = null;

        // onStartLoading() is called when a loader first starts loading data
        @Override
        protected void onStartLoading() {
            if (mTaskData != null) {
                // Delivers any previously loaded data immediately
                deliverResult(mTaskData);
            } else {
                // Force a new load
                forceLoad();
            }
        }

        // loadInBackground() performs asynchronous loading of data
        @Override
        public Cursor loadInBackground() {
            // Will implement to load data

            // Query and load all task data in the background; sort by priority
            // [Hint] use a try/catch block to catch any errors in loading data

            try {
                return getContentResolver().query(TaskContract.TaskEntry.CONTENT_URI,
                        null,
                        null,
                        null,
                        TaskContract.TaskEntry.COLUMN_PRIORITY);

            } catch (Exception e) {
                Log.e(TAG, "Failed to asynchronously load data.");
                e.printStackTrace();
                return null;
            }
        }

        // deliverResult sends the result of the load, a Cursor, to the registered listener
        public void deliverResult(Cursor data) {
            mTaskData = data;
            super.deliverResult(data);
        }
    };

}


/**
 * Called when a previously created loader has finished its load.
 *
 * @param loader The Loader that has finished.
 * @param data The data generated by the Loader.
 */
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Update the data that the adapter uses to create ViewHolders
    mAdapter.swapCursor(data);
}


/**
 * Called when a previously created loader is being reset, and thus
 * making its data unavailable.
 * onLoaderReset removes any references this activity had to the loader's data.
 *
 * @param loader The Loader that is being reset.
 */
@Override
public void onLoaderReset(Loader<Cursor> loader) {
    mAdapter.swapCursor(null);
}

Solution

  • The Solution is to create an Another class and make it static.

    Then Extend AsynctaskLoader from the new Created Static class. Ex - public static class ExtendsAysncTaskLoader extend AsynctaskLoader

    create a member variables - Cursor

    Create a Constructor for the Class with parameters(Context context, Cursor)

    call the Constructor of the parent class using super method and pass the context.

    set the member variable equal to the constructor.

    override onStartLoading and LoadInbackground and implement it as explained in the todo (But be sure you would use the member variable created in the new class) here in the newly created static class.

    In the onCreateLoader method - return the new class with the parameter Ex - return new ExtendsAysncTaskLoader ( this,Cursor);

    The Error will goes away now because we are using a static class named ExampleAsync which inherit the AsyncTaskLoader and Memory Leaks would not occur.

    Example Class -

        public static class ExtendsAysncTaskLoader extends AsyncTaskLoader<Cursor>{
    
            Cursor mTaskData; 
    
        public ExtendsAysncTaskLoader(Context context, Cursor cursor) {
                    super(context);
                    mTaskData = cursor;
                }
    
         // onStartLoading() is called when a loader first starts loading data
        @Override
        protected void onStartLoading() {
            if (mTaskData != null) {
                // Delivers any previously loaded data immediately
                deliverResult(mTaskData);
            } else {
                // Force a new load
                forceLoad();
            }
        }
    
        // loadInBackground() performs asynchronous loading of data
        @Override
        public Cursor loadInBackground() {
            // Will implement to load data
    
            // Query and load all task data in the background; sort by priority
            // [Hint] use a try/catch block to catch any errors in loading data
    
            try {
                return getContentResolver().query(TaskContract.TaskEntry.CONTENT_URI,
                        null,
                        null,
                        null,
                        TaskContract.TaskEntry.COLUMN_PRIORITY);
    
            } catch (Exception e) {
                Log.e(TAG, "Failed to asynchronously load data.");
                e.printStackTrace();
                return null;
            }
        }
    
        // deliverResult sends the result of the load, a Cursor, to the registered listener
        public void deliverResult(Cursor data) {
            mTaskData = data;
            super.deliverResult(data);
        }
    };
    

    }

        OnCreateLoader() Example -
    
        @Override
            public Loader<String> onCreateLoader(int id, final Bundle args) {
    
               Cursor mTaskData = null;                
    
                return new ExtendsAysncTaskLoader(this,mTaskData);
    
    
            }
    

    Hope this Helps