今天項目中遇到了幾個坑,感覺蠻有意思的,紀錄一下。
坑一:奇葩需求
首先需要解決的一個問題如下:
Activity A 以
startActivityForResult()方法啟動了Activity B,然后Activity B可以啟動Activity C,Activity C可以啟動Activity D。需要在B、C和D都可以通過setResult()方法將數(shù)據(jù)返回給A。
這種需求估計不常見,解決這個問題其實并不困難,最容易想到一個方法,就是將C和D都通過startActivityForResult()方式來啟動,但是我一直在想有沒有其他更簡單的方式解決這個問題,畢竟太懶了,不想每個Activity都走一遍這個方法。
網(wǎng)上查了一下,發(fā)現(xiàn)有個好方法可以解決我的問題:在每個Activity(C、D)啟動時,為intent設(shè)置一個Intent.FLAG_ACTIVITY_FORWARD_RESULT,這樣,無論用戶在C、D界面準備退出時,都可以通過setResult()給A返回數(shù)據(jù)。
FLAG_ACTIVITY_FORWARD_RESULT:If set and this intent is being used to launch a new activity from an existing one, then the reply target of the existing activity will be transfered to the new activity.
如果設(shè)置,并且該intent會啟動一個新的Activity,則返回消息的目標會從當前Activity轉(zhuǎn)移到新的Activity中。(在這個案例中,返回消息的目標最開始為B)
坑二:返回無效
但是呢,有一個問題,當我們按返回鍵時,從D返回到C,再用setResult()向A發(fā)送數(shù)據(jù),A是只能接收默認的RESULT_CANCLE,這是不能忍的,既然返回鍵沒有將信息傳遞回去,那么只需要重寫onBackPressed()方法,在里面調(diào)用setResult(),當然,我是寫了BaseActivity,在BaseActivity里面統(tǒng)一處理。代碼如下:
public void onBackPressed() {
setResult(2);
super.onBackPressed();
}
坑三:啟動模式和startActivityForResult()沖突
問題貌似解決了,無論正向還是返回都能傳遞信息。但是任何事物都是有兩面性的,在測試的時候發(fā)現(xiàn)還是有個Activity沒法通過設(shè)置flag來傳遞信息,反復檢查代碼,原來是我在那個Activity里面設(shè)置了singleTask啟動模式,導致了setResult失效,官方文檔說明如下:
For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.
這個問題貌似無解,看來singleTask啟動模式和startActivityForResult()不能同時使用。但是我需要singleTask的效果啊,有其他的方法實現(xiàn)singleTask的效果么?
答案是肯定的,取消了singleTask之后,只需要將該Activity再設(shè)置兩個flag:FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_SINGLE_TOP就能得到相同的效果。
坑四:FLAG_ACTIVITY_CLEAR_TOP != singleTask
關(guān)于FLAG_ACTIVITY_CLEAR_TOP的解釋如下:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
如果設(shè)置,并且這個Activity已經(jīng)在當前運行的棧中,在此Activity之上的所有Activity會被彈出棧,從而該Activity處于棧頂。
看起來和singleTask啟動模式一樣?
其實不然,舉個例子,假設(shè)一個棧中包含這些Activity:A,B,C,D。分別以兩種方法從D啟動B,會有兩種不同的效果:
- 如果D調(diào)用了startActivity()并且以
singleTask模式啟動B,那么,C和D都將被彈出棧,然后B到了棧頂,因此,目前stack的狀況是:A,B。 - 而如果D以
FLAG_ACTIVITY_CLEAR_TOP的方式啟動B的話,C和D同樣回被彈出,但是B自身會先被銷毀一次,然后重新創(chuàng)建一個B。
所以,為了達到和singleTask一樣的效果,我們還需要設(shè)置另外一個flag:
FLAG_ACTIVITY_SINGLE_TOP:
If set, the activity will not be launched if it is already running at the top of the history stack.
當這個Activity位于Activity棧的頂端運行時,不再啟動一個新的。和singleTop啟動模式效果相同。
現(xiàn)在,總算把坑都填滿了。