一個SingleTask與跳轉傳值引發的血案

最近在做項目中遇到這樣一個情況:
Activity A跳轉到Activity B,Activity A設置爲launchMode:singleTask;
Activity B有一個ListView,點擊ListView的一項,返回到Activity A中,同時傳值點擊的是哪一項;(見圖:1-1,代碼:onItemClick)
然後在Activity B中Log出返回的值,但是無論如何就是獲取不到;(見代碼:getBundle,見圖:1-2)

圖 1-1

onItemClick
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent intent = new Intent(BActivity.this, AActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString(StaticValues.KEY_CAR_SERIES, seriesList.get(position));
        bundle.putInt(StaticValues.KEY_CAR_SERIES_ID, position);
        intent.putExtras(bundle);
        startActivity(intent);
        finish();
    }

getBundle
    private void getBundle() {
        Bundle bundle = MainActivity.this.getIntent().getExtras();
        if (null != bundle) {
            Log.d("car", "bundle not null");
            int carSeriesId = bundle.getInt(StaticValues.KEY_CAR_SERIES_ID);
            String carSeries = bundle.getString(StaticValues.KEY_CAR_SERIES);
            Log.d("car", carSeries + "--id=" + carSeriesId);
        } else {
            Log.d("car", "bundle null");
        }
    }


圖 1-2

後來想到,Activity A使用了SingleTask的launchMode,猜想可能跟這個有關,在執行界面跳轉的時候,不會生成新的Activity A實例,所以可能不會接收到傳過來的Bundle裏面的值。於是將Activity A的launchMode改爲了Standard,果然,B傳過來的值,A可以接收到(見圖:1-3),驗證了我的猜想。


圖 1-3

但是爲什麼使用了SingleTask就不能接收到Bundle的傳值呢?
帶着疑問,我們打開了Google API的官網,找到了問題所在,罪魁禍首就是getIntent().
我們現在看看我們使用的SingleTask:

400
圖 1-4

The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent() method, rather than creating a new one.
大致意思就是說一個Activity B如果跳轉到另一個launchMode爲SingleTask的Activity A時,如果task裏面已經有Activity A,那麼跳轉時只需要調用它裏面的onNewIntent()方法,而不是另外創建一個新的Activity A.

那麼onNewIntent()到底是什麼?如何使用它呢?
帶着好奇,我們來查詢onNewIntent()這個方法:


圖 1-5

onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it.
這句話的大致意思是說,如果你的Task裏面已經有Activity A實例,且其他其他界面跳轉到A時不會產生新的A的實例時,onNewIntent()會被調用,通常這時候這裏面的Intent是用來重新啓動那個已經存在的A實例的。
An activity will always be paused before receiving a new intent, so you can count on onResume() being called after this method.
我們的Activity A在接收到一個新的Intent的時候,會被pause掉,所以我們在調用onNewIntent()的時候,記得在之後調用onResume().(雖然讀清楚了字面意思,但是還是不知道具體怎麼操作-_-#)
這裏我們注意一下這句話:
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
我們之前在getBundle()方法裏(見上面代碼:getBundle)調用的是getIntent()方法,這個方法返回的是最原始啓動Actvity A的Intent,而不是由Activity B跳轉到Activity A使用的Intent。所以我們想要拿到Activity B跳到Activity A使用的Intent,我們要使用setIntent(Intent)方法。

那麼我們如何使用setIntent(Intent)呢?
由上述表達的意思,我們隱約可以理解,setIntent(Intent)在onNewIntent(Intent)裏面,那麼setIntent方法的參數無疑使用的也是onNewIntent的參數。可是onNewIntent(Intent)方法是如何調用的呢?我們回到了上一個問題。
於是帶着思考,我們去度娘了一下,結果找到了這樣的代碼:
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

表達的意思和上述onNewIntent的英文解釋一樣,當有一個Activity B跳轉到我們的singleTask Activity A時,我們在getIntent()前會先執行onNewIntent()方法,在這個方法裏,我們將接收到的新的Intent覆蓋了第一次啓動Activity A用的Intent,這樣我們在getIntent()的時候,拿到的Intent就是帶有B傳給A帶有Bundle值的Intent了。
我們將onNewIntent(Intent)方法寫在了我們的Activity A裏面,成功的得到了B傳給A的數據(效果如圖:1-3)。

PS: 第一次在CSDN裏面寫博客,有不足的地方,希望過來人指點,請多指教!
發佈了22 篇原創文章 · 獲贊 16 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章