我在代码中收到一条警告:
This AsyncTask class should be static or leaks might occur (anonymous android.os.AsyncTask)
完整的警告是:
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.
这是我的代码:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
我该如何纠正这个问题?
最佳答案
如何使用静态内部 AsyncTask 类
为防止泄漏,您可以将内部类设为静态。但是,问题在于您不再有权访问 Activity 的 UI View 或成员变量。您可以传入对 Context
的引用,但同样会面临内存泄漏的风险。 (如果 AsyncTask 类对它有强引用,Android 不能在 Activity 关闭后对它进行垃圾收集。)解决方案是对 Activity(或您需要的任何 Context
)进行弱引用。
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;
}
}
}
注意事项
- 据我所知,这种类型的内存泄漏危险一直存在,但我只是在 Android Studio 3.0 中才开始看到警告。许多主要的
AsyncTask
教程仍然没有处理它(参见 here 、 here 、 here 和 here )。 - 如果您的
AsyncTask
是顶级类,您也将遵循类似的过程。静态内部类与 Java 中的顶级类基本相同。 如果您不需要 Activity 本身但仍需要 Context(例如,显示
Toast
),则可以传入对应用上下文的引用。在这种情况下,AsyncTask
构造函数如下所示:private WeakReference<Application> appReference; MyTask(Application context) { appReference = new WeakReference<>(context); }
- 有一些争论可以忽略这个警告而只使用非静态类。毕竟,AsyncTask 的生命周期很短(最长几秒钟),无论如何它都会在完成时释放对 Activity 的引用。见 this和 this .
- 优秀文章:How to Leak a Context: Handlers & Inner Classes
Kotlin
在 Kotlin 中只需 don't include the inner
keyword对于内部类。这使其默认为静态。
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
}
}
}
关于android - 警告 : This AsyncTask class should be static or leaks might occur,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44309241/