如何判断我的上下文是否仍然有效?

时间:2011-10-21 22:48:00

标签: java android

我正在处理一个相当常见的情况 - 通过网络下载一些数据,然后更新视图以显示它。显然,我想在后台进行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吗?

5 个答案:

答案 0 :(得分:20)

如果您的ContextActivity,则可以检查它是否已完成或已完成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
    }