问题描述
我在我的代码中收到一条警告,指出:
I am getting a warning in my code that states:
这个 AsyncTask 类应该是静态的,否则可能会发生泄漏(匿名 android.os.AsyncTask)
完整的警告是:
此 AsyncTask 类应该是静态的,否则可能会发生泄漏(匿名 android.os.AsyncTask)静态字段会泄漏上下文.非静态内部类具有对其外部类的隐式引用.例如,如果该外部类是 Fragment 或 Activity,则此引用意味着长时间运行的处理程序/加载程序/任务将持有对该活动的引用,以防止其被垃圾收集.类似地,对来自这些运行时间较长的实例的活动和片段的直接字段引用可能会导致泄漏.ViewModel 类不应指向视图或非应用程序上下文.
这是我的代码:
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 视图或成员变量.您可以传入对 Context
的引用,但是您会面临相同的内存泄漏风险.(如果 AsyncTask 类对它有强引用,Android 不能在 Activity 关闭后对其进行垃圾收集.)解决方案是对 Activity(或您需要的任何 Context
)进行弱引用.
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;
}
}
}
注意事项
- 据我所知,这种类型的内存泄漏危险一直存在,但我才开始在 Android Studio 3.0 中看到警告.许多主要的
AsyncTask
教程仍然没有处理它(参见 这里、这里、此处 和 此处). - 如果您的
AsyncTask
是顶级类,您也将遵循类似的过程.静态内部类与 Java 中的顶级类基本相同. 如果您不需要 Activity 本身但仍需要 Context(例如,显示
Toast
),您可以传入对应用程序上下文的引用.在这种情况下,AsyncTask
构造函数看起来像这样: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 theAsyncTask
constructor would look like this:private WeakReference<Application> appReference; MyTask(Application context) { appReference = new WeakReference<>(context); }
- 有一些理由可以忽略此警告并仅使用非静态类.毕竟,AsyncTask 的生命周期很短(最长几秒钟),无论如何它都会在完成时释放对 Activity 的引用.请参阅此和这个.
- 优秀文章:如何泄漏上下文:处理程序&内部类
在 Kotlin 中,只需 不要为内部类包含
inner
关键字.这使其默认为静态.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 } } }
这篇关于警告:这个 AsyncTask 类应该是静态的,否则可能会发生泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- 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