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);
}
}
}
Related
I have a class which extends Asynctask and I want to access my activity or context of it. Every time I try, I get cannot be referenced from a static context or Unable to add window -- token null is not for an application.
ps: I'm not using fragments, it's only activity.
You should be careful when passing context in an async task; you could create leaks. You can interact with your activity in an async task if you create a weak reference to it when you declare your task and acquire the reference when you need to use it by calling .get() on it.
private static class YourAsyncTask extends AsyncTask<String, String, String> {
Private WeakReference<YourActivity> weakReference;
YourAsyncTask(YourActivity context) {
weakReference = new WeakReference<>(context);
}
…
#Override
Protected void onPostExecute(String string) {
YourActivity activity = weakReference.get();
}
}
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'm having trouble implementing a delegate in my android app.
In my GetData class I have nested asynctask, and I need to notify my main activity when all the work has actually finished.
I came up with this answer from Mohd Mufiz
What is the best way for AsyncTask to notify parent Activity about completion?
But I always get stuck at the same point:
in my GetData class I call a constructor with the delegate as only argument:
public class GetData {
private TaskDelegate delegate;
public GetData(TaskDelegate delegate) {
this.delegate = delegate;
}
...
}
In my main activity I don't know what I have to pass to get it working:
GetData getData = new GetData(**???**);
Going from the question you linked to, that defined TaskDelegate as :
public interface TaskDelegate {
public void taskCompletionResult(String result);
}
You can pass GetData any instance of a class that implements TaskDelegate - but typically, that would be the object that creates it - ie. your main activity (and so, therefore, it would also implement "void taskCompletionResult(String result);"). That then means you can pass "this" to GetData's constructor, so :
public class MyMainActivity implements TaskDelegate {
public void someMethod() {
GetData getData = new GetData(this);
}
public void taskCompletionResult(String result) {
// do stuff
}
}
So from reading/research about memory leaks it suggests to make all inner classes static to avoid memory leaks. However, by looking at the SDK samples (specifically TicTacToeLib) they implement their callbacks without the use of static inner classes. Will this cause a memory leak? If not, why?
private Handler mHandler = new Handler(new MyHandlerCallback());
private class MyHandlerCallback implements Callback {
public boolean handleMessage(Message msg) {
if (msg.what == MSG_COMPUTER_TURN) {
// Pick a non-used cell at random. That's about all the AI you need for this game.
State[] data = mGameView.getData();
int used = 0;
while (used != 0x1F) {
int index = mRnd.nextInt(9);
if (((used >> index) & 1) == 0) {
used |= 1 << index;
if (data[index] == State.EMPTY) {
mGameView.setCell(index, mGameView.getCurrentPlayer());
break;
}
}
}
finishTurn();
return true;
}
return false;
}
}
Yes, this sample will cause a leak in case it keeps a Message in the queue. But it's not a very severe leak since it is usually limited to a rather short amount of time.
But there is a rather simple way to prevent the leak:
Put the following two classes into your project
/** Callback that decouples the wrapped Callback via WeakReference */
public class SafeCallback implements Handler.Callback {
private final WeakReference<Handler.Callback> mCallback;
public SafeCallback(Handler.Callback callback) {
mCallback = new WeakReference<Handler.Callback>(callback);
}
#Override
public boolean handleMessage(Message msg) {
Handler.Callback callback = mCallback.get();
if (callback != null)
return callback.handleMessage(msg);
// else warn, return true, ..?
return false;
}
}
/** replacement for anonymous inner Handler implementations */
public abstract class SafeHandler implements Handler.Callback {
#Override
public abstract boolean handleMessage(Message msg);
public final Handler get() {
return new Handler(new SafeCallback(this));
}
public final Handler get(Looper looper) {
return new Handler(looper, new SafeCallback(this));
}
}
And now you can use Handler / Callback almost as you used to do but it's no longer leaking.
So either like
public class TestActivity extends Activity {
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new SafeHandler() { // << instead of new Handler() {
#Override
public boolean handleMessage(Message msg) {
// handle message
return false;
}
}.get(); // << Notice this added .get()
}
}
or like
public class TestActivity2 extends Activity implements Handler.Callback {
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler(new SafeCallback(this)); // << wrapped in SafeCallback
}
#Override
public boolean handleMessage(Message msg) {
// handle message
return false;
}
}
The leak problem with Handler is that each Message / Runnable (which is actually wrapped in a Message) knows it's target, i.e. has a hard reference to the Handler or Callback. And if that target is a non-static inner class, it will have an implicit hard reference to the outer class which is typically an Activity.
That means that as long as there are Messages enqueued for your Handler, your whole Activity can't be garbage collected.
To solve this issue that chain of hard references from Message to Activity has to be broken. The SafeCallback class does exactly that by keeping just a WeakReference towards your Activity.
That means, the Message has now a hard reference to SafeCallback but the part bind there can now be garbage collected. In case that happens Handler.Callback callback = mCallback.get(); will turn out null and the Message is simply discarded. There is no more useful target anyways. It is still leaking the SafeCallback itself but that's a pretty much empty class so it won't lead to problems.
I would approach it from the standpoint of what use case are you trying to solve, and not what the language itself is doing. If you "nested class" (not inner class because inner classes can't be static) needs to be able to call non-static methods on its parent class, or read non-static members, then you don't have much choice but to make it non-static. If you can get away with not accessing any of the parent class's non-static resources, then by all means do so (you'll save some memory that way anyways). However, if you're worried about memory leaks and you're going to make the nested class private as in your example, then you really shouldn't have anything to worry about because instances of that class can only be created locally to the parent class (unless you create a static member of the parent class that holds a reference to an instance of the nested class, in which case that object would be around until the parent class gets unloaded by the VM).
In summary, I wouldn't personally worry too much about whether or not your nested class is declared as static or non-static, but focus more on the lifecycle of instances of that class, if you're worried about leaking memory.
I am developing an application in which i need to send the value of the asynctask's onPostExecute method's result in to the previous activity , ie the activity in which the aync task is being called.pls put some codes. Anyhelp is appreciated
Two ways:
Declare class extending AsyncTask as private class in parent Activity
Pass Handler or Activity itself as param of class extending AsyncTask
If I were you, I'd follow the first option.
Look at DOCS:
class MyActivitySubclass extends Activity {
function runOnPostExecute(){
// whatever
}
private class MyTask extends AsyncTask<Void, Void, Void> {
void doInBackground(Void... params){
// do your background stuff
}
void onPostExecute(Void... result){
runOnPostExecute();
}
}
}
Note 1
Code placed in body of function onPostExecute is already run on Activity thread, you should just mention that this keywords leads to MyTask.this and not MyActivitySubclass.this
Well if your AsyncTask is an inner class, you could simply call a method in your activity from onPostExecute():
public class MyActivity extends Activity {
public void someMethod(String someParam) {
// do something with string here
}
public class InnerTask extends AsyncTask<...> {
protected void onPostExecute(result) {
someMethod(Send parameters);
}
}
}
The onPostExecute method is fired on the main UI thread, so anything done there is already on the AsyncTasks caller.
http://developer.android.com/reference/android/os/AsyncTask.html
Fire an event in the OnPostExecute.
Its an add on to the answer by Marek Sebera, he pointed to use a handler. To keep the code simple and intuitive use an interface. This isn't alien concept, we use it all the time for callback functions (eg: OnClickListner etc..). The code would look some thing like this.
public class InnerTask extends AsyncTask<...>
{
interface ResultHandler
{
void gotResult(<> result);
}
private ResultHandler myResult;
//constructor
public InnerTask(....params...,ResultHandler callback)
{
...
this.myResult = callback;
}
protected void onPostExecute(<>result)
{
...
myResult.gotResult(result);
}
}
public class MyActivity extends Activity implements InnerTask.ResultHandler
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
//do something
//if you want the InnerTask to execute here
InnerTask i = new InnerTask(....params...,this); //send 'this' as parameter
i.execute();
}
#Override
public void gotResult(<> result)
{
//from onPostExecute
}
}
If we want to use the same AsynTask class at multiple sites we can use this type of implementation instead of using nested classes implementation.