簡體   English   中英

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

[英]How can I tell if my context is still valid?

我現在正在處理一個相當普遍的情況 - 通過網絡下載一些數據,然后更新視圖以顯示它。 顯然,我想在后台進行網絡下載,然后在主 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 使事情變得更好嗎?

如果您的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();

您真正想要使用的是AsyncTaskLoader 這些是我在 Android API 中最喜歡的新類。 我一直在使用它們,它們就是為了解決這樣的問題。 您不必擔心何時停止下載或類似的事情。 所有線程邏輯都會為您處理,包括告訴線程在活動已關閉時停止。 只需在loadInBackground()方法中說出您想做什么。 請注意,如果您正在為低於 3.0 的 API 進行開發,您仍然可以通過Android 支持包訪問所有加載器。

如果您使用匿名類,它們將具有對外部類的內部引用,因此它不會因為其他引用已被清除而突然變得不可訪問。 AsyncTask實際上不會改變任何東西,它使用類似的機制來通知結果。

您可以使用loader ,它們旨在與活動生命周期同步。 它們僅在 Android 3.0 之后可用,但您可以使用支持包在任何 1.6 或更高版本的設備上使用它們。

還有一個更簡單的解決方案,您可以只使用一個布爾字段來指示活動是否已經消失。 你應該在onPause()設置這個字段(或者當你認為你不再需要通知時)並在你顯示 toast 時檢查它。 您甚至不必使用同步,因為該字段僅限於主線程,因此絕對安全。 順便說一句,如果您在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();
    }
}

我通常使用Weak Reference來避免在視圖中泄漏上下文

上下文的弱引用

private var mContext: WeakReference<Context?>? = null

分配上下文

mContext = WeakReference(appContext)

獲取上下文

mContext .get()

驗證上下文

  if (mContext?.get() is Activity &&
        (mContext?.get()  as Activity).isFinishing){
            return
    }

庫蒂斯是對的。 但是,如果你真的想保持簡單,你可以試試這個:

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 是您應該如何做事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM