I have created as asynctask to upload data to a server as below. But it shows this warning eaxctly at class AsyncTaskUploadClass. "This AsyncTask class should be static or leaks might occurs......" I have read and tried the weak reference style but i am unable to integrate it in this code. Any leads will be appreciated.
public void ImageUploadToServerFunction(){
final String imageName1 = GetImageNameEditText1.trim();
final String userName = GetUserName.trim();
final String imageView1 = getStringImage1(bitmap1);
class AsyncTaskUploadClass extends AsyncTask<Void,Void,String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(UploadActivity.this,"Your Data is Uploading....",false,false);
}
#Override
protected void onPostExecute(String string1) {
super.onPostExecute(string1);
progressDialog.dismiss();
}
#Override
protected String doInBackground(Void... params) {
ImageProcessClass imageProcessClass = new ImageProcessClass();
HashMap<String,String> HashMapParams = new HashMap<>();
HashMapParams.put(ImageName1, imageName1);
HashMapParams.put(UserName, userName);
HashMapParams.put(ImagePath1, imageView1);
return imageProcessClass.ImageHttpRequest(ServerUploadPath, HashMapParams);
}
}
AsyncTaskUploadClass AsyncTaskUploadClassOBJ = new AsyncTaskUploadClass();
AsyncTaskUploadClassOBJ.execute();
}
It's in the nature of inner classes of Java- a class within a class has a hidden reference to the parent instance. That can cause memory leaks. The way to avoid that is to make it a static inner class- static class Foo. This will cause it to remove the hidden reference, but the inner class will no longer be able to reference functions or member variables of the parent.
More practically- this type of AsyncTask, while it technically can cause a temporary leak, is fairly safe as long as the doInBackground function terminates in a reasonable amount of time. For this class, if imageProcessClass.ImageHttpReques() runs and terminates (with either a timeout error or by finishing its work) in a reasonable amount of time it isn't a leak worry- it just that the parent class, which looks like an Activity, will not be freed until it does so. So it will force the parent class to stick around for a second or two longer than needed if the Activity is finished but the request is processing.
Related
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 ??
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
Create a separate class that implements AsyncTask, then in your activity instantiate it, and run the execute method.
I am getting a warning in my code that states:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
The complete warning is:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
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.
This is my code:
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
How do I correct this?
How to use a static inner AsyncTask class
To prevent leaks, you can make the inner class static. The problem with that, though, is that you no longer have access to the Activity's UI views or member variables. You can pass in a reference to the Context but then you run the same risk of a memory leak. (Android can't garbage collect the Activity after it closes if the AsyncTask class has a strong reference to it.) The solution is to make a weak reference to the Activity (or whatever Context you need).
public class MyActivity extends AppCompatActivity {
int mSomeMemberVariable = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start the AsyncTask, passing the Activity context
// in to a custom constructor
new MyTask(this).execute();
}
private static class MyTask extends AsyncTask<Void, Void, String> {
private WeakReference<MyActivity> activityReference;
// only retain a weak reference to the activity
MyTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
#Override
protected String doInBackground(Void... params) {
// do some long running task...
return "task finished";
}
#Override
protected void onPostExecute(String result) {
// get a reference to the activity if it is still there
MyActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
// modify the activity's UI
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
// access Activity member variables
activity.mSomeMemberVariable = 321;
}
}
}
Notes
As far as I know, this type of memory leak danger has always been true, but I only started seeing the warning in Android Studio 3.0. A lot of the main AsyncTask tutorials out there still don't deal with it (see here, here, here, and here).
You would also follow a similar procedure if your AsyncTask were a top-level class. A static inner class is basically the same as a top-level class in Java.
If you don't need the Activity itself but still want the Context (for example, to display a Toast), you can pass in a reference to the app context. In this case the AsyncTask constructor would look like this:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
There are some arguments out there for ignoring this warning and just using the non-static class. After all, the AsyncTask is intended to be very short lived (a couple seconds at the longest), and it will release its reference to the Activity when it finishes anyway. See this and this.
Excellent article: How to Leak a Context: Handlers & Inner Classes
Kotlin
In Kotlin just don't include the inner keyword for the inner class. This makes it static by default.
class MyActivity : AppCompatActivity() {
internal var mSomeMemberVariable = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start the AsyncTask, passing the Activity context
// in to a custom constructor
MyTask(this).execute()
}
private class MyTask
internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {
private val activityReference: WeakReference<MyActivity> = WeakReference(context)
override fun doInBackground(vararg params: Void): String {
// do some long running task...
return "task finished"
}
override fun onPostExecute(result: String) {
// get a reference to the activity if it is still there
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
// modify the activity's UI
val textView = activity.findViewById(R.id.textview)
textView.setText(result)
// access Activity member variables
activity.mSomeMemberVariable = 321
}
}
}
Non-static inner classes holds a reference to the containing class. When you declare AsyncTask as an inner class, it might live longer than the containing Activity class. This is because of the implicit reference to the containing class. This will prevent the activity from being garbage collected, hence the memory leak.
To solve your problem, either use static nested class instead of anonymous, local, and inner class or use top-level class.
This AsyncTask class should be static or leaks might occur because
When Activity is destroyed, AsyncTask (both static or non-static) still running
If inner class is non-static (AsyncTask) class, it will have reference to the outer class (Activity).
If a object has no references point to it, Garbage Collected will release it. If a object is unused and Garbage Collected can not release it => leak memory
=> If AsyncTask is non-static, Activity won't release event it is destroyed => leak
Solution for update UI after make AsyncTask as static class without leak
1) Use WeakReference like #Suragch answer
2) Send and remove Activity reference to (from) AsyncTask
public class NoLeakAsyncTaskActivity extends AppCompatActivity {
private ExampleAsyncTask asyncTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// START AsyncTask
asyncTask = new ExampleAsyncTask();
asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
#Override
public void onExampleAsyncTaskFinished(Integer value) {
// update UI in Activity here
}
});
asyncTask.execute();
}
#Override
protected void onDestroy() {
asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
private ExampleAsyncTaskListener listener;
#Override
protected Integer doInBackground(Void... voids) {
...
return null;
}
#Override
protected void onPostExecute(Integer value) {
super.onPostExecute(value);
if (listener != null) {
listener.onExampleAsyncTaskFinished(value);
}
}
public void setListener(ExampleAsyncTaskListener listener) {
this.listener = listener;
}
public interface ExampleAsyncTaskListener {
void onExampleAsyncTaskFinished(Integer value);
}
}
}
I am getting a warning in my code that states:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
The complete warning is:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
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.
This is my code:
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
How do I correct this?
How to use a static inner AsyncTask class
To prevent leaks, you can make the inner class static. The problem with that, though, is that you no longer have access to the Activity's UI views or member variables. You can pass in a reference to the Context but then you run the same risk of a memory leak. (Android can't garbage collect the Activity after it closes if the AsyncTask class has a strong reference to it.) The solution is to make a weak reference to the Activity (or whatever Context you need).
public class MyActivity extends AppCompatActivity {
int mSomeMemberVariable = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start the AsyncTask, passing the Activity context
// in to a custom constructor
new MyTask(this).execute();
}
private static class MyTask extends AsyncTask<Void, Void, String> {
private WeakReference<MyActivity> activityReference;
// only retain a weak reference to the activity
MyTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
#Override
protected String doInBackground(Void... params) {
// do some long running task...
return "task finished";
}
#Override
protected void onPostExecute(String result) {
// get a reference to the activity if it is still there
MyActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
// modify the activity's UI
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
// access Activity member variables
activity.mSomeMemberVariable = 321;
}
}
}
Notes
As far as I know, this type of memory leak danger has always been true, but I only started seeing the warning in Android Studio 3.0. A lot of the main AsyncTask tutorials out there still don't deal with it (see here, here, here, and here).
You would also follow a similar procedure if your AsyncTask were a top-level class. A static inner class is basically the same as a top-level class in Java.
If you don't need the Activity itself but still want the Context (for example, to display a Toast), you can pass in a reference to the app context. In this case the AsyncTask constructor would look like this:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
There are some arguments out there for ignoring this warning and just using the non-static class. After all, the AsyncTask is intended to be very short lived (a couple seconds at the longest), and it will release its reference to the Activity when it finishes anyway. See this and this.
Excellent article: How to Leak a Context: Handlers & Inner Classes
Kotlin
In Kotlin just don't include the inner keyword for the inner class. This makes it static by default.
class MyActivity : AppCompatActivity() {
internal var mSomeMemberVariable = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start the AsyncTask, passing the Activity context
// in to a custom constructor
MyTask(this).execute()
}
private class MyTask
internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {
private val activityReference: WeakReference<MyActivity> = WeakReference(context)
override fun doInBackground(vararg params: Void): String {
// do some long running task...
return "task finished"
}
override fun onPostExecute(result: String) {
// get a reference to the activity if it is still there
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
// modify the activity's UI
val textView = activity.findViewById(R.id.textview)
textView.setText(result)
// access Activity member variables
activity.mSomeMemberVariable = 321
}
}
}
Non-static inner classes holds a reference to the containing class. When you declare AsyncTask as an inner class, it might live longer than the containing Activity class. This is because of the implicit reference to the containing class. This will prevent the activity from being garbage collected, hence the memory leak.
To solve your problem, either use static nested class instead of anonymous, local, and inner class or use top-level class.
This AsyncTask class should be static or leaks might occur because
When Activity is destroyed, AsyncTask (both static or non-static) still running
If inner class is non-static (AsyncTask) class, it will have reference to the outer class (Activity).
If a object has no references point to it, Garbage Collected will release it. If a object is unused and Garbage Collected can not release it => leak memory
=> If AsyncTask is non-static, Activity won't release event it is destroyed => leak
Solution for update UI after make AsyncTask as static class without leak
1) Use WeakReference like #Suragch answer
2) Send and remove Activity reference to (from) AsyncTask
public class NoLeakAsyncTaskActivity extends AppCompatActivity {
private ExampleAsyncTask asyncTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// START AsyncTask
asyncTask = new ExampleAsyncTask();
asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
#Override
public void onExampleAsyncTaskFinished(Integer value) {
// update UI in Activity here
}
});
asyncTask.execute();
}
#Override
protected void onDestroy() {
asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
private ExampleAsyncTaskListener listener;
#Override
protected Integer doInBackground(Void... voids) {
...
return null;
}
#Override
protected void onPostExecute(Integer value) {
super.onPostExecute(value);
if (listener != null) {
listener.onExampleAsyncTaskFinished(value);
}
}
public void setListener(ExampleAsyncTaskListener listener) {
this.listener = listener;
}
public interface ExampleAsyncTaskListener {
void onExampleAsyncTaskFinished(Integer value);
}
}
}
I am pretty new to async tasks, but the few I have created for my app entail accessing class level variables and I have had a few null pointer exceptions sometimes in the doInBackground() for these tasks on real-world devices.
I believe this is because these variables should not really ever be accessed from within the async task, but instead passed in through the constructor or params etc. For example if I transition to activity B and an async task is still running from activity A, all of A's variables should become null shouldn't they?
And if accessing these variables should never be used from within the context of an async task, shouldn't the IDE (Android Studio in my case) warn me this is a dangerous action?
Edit: Wow so much help so quickly! Hopefully this will help others in the future too. Here is some code which is roughly what I was thinking about:
public class MyActivity extends ActionBarActivity {
private Context mContext;
private User mUser;
private ProgressDialog mProgressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
mProgressDialog = new ProgressDialog(mContext);
mUser = new User();
new MyAsyncTask.execute();
}
private class MyAsyncTask extends AsyncTask<Params, Integer, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setCancelable(true);
mProgressDialog.setMessage("My message");
mProgressDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
}
#Override
protected Void doInBackground(Params... params) {
Toast.makeText(mContext, "In doInBackground()", Toast.LENGTH_LONG).show();
mUser.someMethodThatTakesTime();
return null;
}
#Override
protected void onPostExecute(Void params) {
mProgressDialog.dismiss();
//Possibly launch another activity
}
}
}
You should definitely avoid using AsyncTask as an Inner Class in your Activity. Inner classes contain implicit strong references to their container class, so you run the risk of getting null pointers like you experienced during the Activity Lifecycle. And it does not just happen if Activity B goes on top of Activity A. It could happen if you rotate the device as well.
The problem is the Activity Lifecycle (which is why your IDE is not giving you warnings). For a configuration change (such as rotation), or in low memory situations, the Activity can be destroyed and recreated. But your AsyncTask will still be tied to the old activity.
There are a lot of threads about this:
https://stackoverflow.com/a/8550351/1856960
https://stackoverflow.com/a/16305144/1856960
You can also look into third party frameworks designed to deal with this:
https://github.com/stephanenicolas/robospice
Google around for more info too, this is hardly an exhaustive list.
I provide you two links.
firstly read and try to understanding
I expected that you will solve any problem about Android Asynctask problems in future.
link 1 Android Asynctask Example
and
link 2 Android Background Processing with Handlers and AsyncTask and Loaders - Tutorial
Best of Luck!
I'm currently doing something like this in the AsyncTask's onPostExecute method, where NewTask is not the current task that's executing:
private class OlderTask extends AsyncTask<String, Void, Integer> {
//other functions (not important)
#Override
protected void onPostExecute(Integer result) {
new NewTask().execute(null, null);
}
}
I'm wondering if this is a bad idea. Will doing so cause GC for the OlderTask to wait for the NewTask? Are there any other possible problems with using such an approach?
And if this is a problem, how can I rectify it?
Unless NewTask is inner non static class in OlderTask it will not prevent GC from collecting OlderTask unless you store reference to it in some other way.
But even if GC will wait until NewTask is done it should not be a big deal unless you save lot of data in OlderTask or create lots of copies of OlderTask.
So if your design requires doing that, it's ok. But it surely cleaner not to have chained tasks.
I use a callback method, So when result comes to onPostExecute I call another AsynkTask from UI, I think it is good idea, Let me know what do you think.
public class PatientSearchController extends AsyncTask < String, Void, String > {
private PatientSearchResultHandler handler = null;
public void onResultHandler(PatientSearchResultHandler handler) {
this.handler = handler;
}
#Override
protected String doInBackground(String...params) {
}
#Override
protected void onPostExecute(String result) {
this.handler.onResultSuccessHandler(result);
}
}