我正在处理一个相当常见的情况 - 通过网络下载一些数据,然后更新视图以显示它。显然,我想在后台进行Web下载,然后在主UI线程上更新视图。现在看看我的代码,我有点担心我的Activity和它的UI元素在我更新它们之前被杀掉了。这就是我的想法的本质:
Thread update = new Thread() {
public void run() {
final Data newData = requestData();
if (newData != null) {
post(new Runnable() {
public void run() {
Toast.makeText(MyClass.this, "I'll do things here that depend on my context and views being valid", Toast.LENGTH_SHORT).show();
}
});
}
}
};
update.start();
似乎有可能在我下载数据时,活动可能会被破坏。那么会发生什么?我的线程会继续执行吗?我最终会试图访问死对象吗?
通常我是通过AsycTask来做的,但是这次工作似乎很简单,只是内联线程启动线程的东西。我会改用AsyncTask吗?
答案 0 :(得分:20)
如果您的Context
是Activity
,则可以检查它是否已完成或已完成isFinishing()
方法:
if ( context instanceof Activity ) {
Activity activity = (Activity)context;
if ( activity.isFinishing() ) {
return;
}
}
Toast.makeText(context, "I'll do things here that depend on my context and views being valid", Toast.LENGTH_SHORT).show();
答案 1 :(得分:6)
您真正想要使用的是AsyncTaskLoader。这些是我在Android API中最喜欢的课程。我一直都在使用它们,它们就像这样解决了问题。您不必担心何时停止下载或类似的事情。所有线程逻辑都会为您处理,包括告诉线程在活动已关闭时停止。只需说明你想在loadInBackground()方法中做什么。请注意,如果您正在为低于3.0的API进行开发,您仍然可以通过Android Support Package访问所有加载器。
答案 2 :(得分:2)
如果使用匿名类,它们将具有对外部类的内部引用,因此它不会突然变得无法访问,因为其他引用已被清除。 AsyncTask
实际上并没有改变任何东西,它使用类似的机制来通知结果。
您可以使用loaders,它们旨在与活动生命周期保持同步。它们仅在Android 3.0之后可用,但您可以使用support package在1.6或更高版本的任何设备上使用它们。
甚至有一个更简单的解决方案,您可以使用一个布尔字段来指示活动是否已经消失。您应该在onPause()
中设置此字段(或者当您认为不再需要通知时),并在显示吐司时检查它。您甚至不必使用同步,因为此字段仅限于主线程,因此它绝对安全。顺便说一句,如果你在onDestroy()
之外的其他地方更改此字段,请不要忘记添加一个语句,该语句会在对应方法中重置您的字段。
public class MyActivity extends Activity {
private boolean activityDestroyed = false;
@Override
protected void onDestroy() {
activityDestroyed = true;
}
private void updateData() {
new Thread() {
@Override
public void run() {
final Data newData = requestData();
if (newData == null) return;
runOnUiThread(new Runnable() {
public void run() {
if (activityDestroyed) return;
Toast.makeText(MyActivity.this, "Blah",
Toast.LENGTH_SHORT).show();
}
});
}
}.start();
}
}
答案 3 :(得分:0)
Kurtis是对的。但是,如果您真的想保持简单,可以试试这个:
class MyActivity extends Activity {
static MyActivity context;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
MyActivity.context = this;
}
@Override
public void onDestroy() {
super.onDestroy();
MyActivity.context = null;
}
}
然后你只需在你的类中使用MyActivity.context
(并在那里检查null)。如果您希望当应用程序在后台时甚至不显示toast,请改用onPause / onResume。
同样,这是一种快速而懒惰的方法。 AsyncTask或AsyncTaskLoader就是你应该做的事情。
答案 4 :(得分:0)
我通常使用Weak Reference
来避免视图中的上下文泄漏
上下文参考不足
private var mContext: WeakReference<Context?>? = null
分配上下文
mContext = WeakReference(appContext)
获取上下文
mContext .get()
验证上下文
if (mContext?.get() is Activity &&
(mContext?.get() as Activity).isFinishing){
return
}