如何使用静态内部AsyncTask类
为了防止泄漏,可以将内部类设为静态。但是,这样做的问题是您不再有权访问活动的UI视图或成员变量。您可以传递对的引用,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
那里的许多主要教程仍然不涉及它(请参见此处,此处,此处和此处)。
- 如果您
AsyncTask
是顶级班,则您也将遵循类似的过程。静态内部类基本上与Java中的顶级类相同。
如果您不需要Activity本身,但仍想要Context(例如显示Toast
),则可以传递对应用程序上下文的引用。在这种情况下,AsyncTask
构造函数将如下所示:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- 有一些参数可以忽略此警告,而仅使用非静态类。毕竟,AsyncTask的寿命很短(最长为几秒钟),并且无论如何完成它都会释放对Activity的引用。看到这个和这个。
- 优秀文章:如何泄漏上下文:处理程序和内部类
科特林
在Kotlin中,只是不要包括inner
内部类的关键字。默认情况下将其设为静态。
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
}
}
}