我在我的 Activity 类中初始化了一个成员变量
private String test = new String("A");
然后我用它在从 Activity 启动的匿名 AsyncTask 的 doInBackground()
方法中写入一个耗时很长的循环
new AsyncTask<Void, Void, Void>() {
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(Void result) {
}
@Override
protected Void doInBackground(Void... params) {
for (int j = 10; j >= 0; j--) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("DOINBACKGROUND ", test);
}
}.execute();
问题:
当我在 Asynctask
仍在执行时离开 Activity,并且在 Activity 的 onDestroy()
执行之后,我在日志中看到成员变量是还活着,没有被摧毁。有人可以向我解释这怎么可能吗?
悬赏问题:
成员变量仍然存在,因为即使在 onDestroy()
之后,由于 gc 条件和 gc 优先级,它还没有被垃圾化。这没关系。
但我怀疑是不是
- 'test' 成员变量(和 Activity 的上下文)在引用 asynctask 结束它的内容之前不会被垃圾化,因此 asynctask 可以始终并且肯定地完成它的
doInBackground()
而不会崩溃(尽管有一个临时内存消耗)
或者相反
- 无论 asynctask 是否运行,'test' 成员变量迟早会被垃圾处理,可能会导致 asysnctask 崩溃
最佳答案
不要混淆垃圾回收和 Activity 生命周期。
一旦所有从 GC 根对象追踪到它的引用都消失了,一个对象就可以被垃圾收集。
onDestroy()
是 Activity 生命周期的一部分。本质上,框架已完成 Activity ,并放弃了它可能持有的对 Activity 和相关资源的任何引用。
当你实例化一个匿名内部类时,它会得到一个对父对象的隐式引用。换句话说,匿名内部类始终是非静态内部类。此父引用是对您的 Activity
的引用。然后,您通过调用 execute()
将异步任务对象传递给执行程序,执行程序会在需要时保留异步任务引用,同时防止引用的 Activity 被垃圾收集.
Thus the asynctask in my snippet example will complete its doInBackground() always and surely without crashing due to NPE?
是的。但请考虑以下几点:
使您的内部类
静态
,除非它们特别需要访问父对象。由于匿名内部类始终是非静态
,因此使它们成为非匿名的。在具有独立生命周期的对象(例如 Activity 或 fragment )中混合异步操作很脆弱,最好避免。问题包括例如取消、将结果传递给已消失的对象,并保留对 Activity 等昂贵对象的 GC 预防引用。
关于java - Activity 的成员范围和 Asynctask,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31031628/