編輯:關於Android編程
Android官網介紹Activity的啟動模式時比較含糊,介紹Application,Activity,Task,Process,Thread等概念以及它們之間的關系時,也沒有說得清楚。大家看了Android官網對Activity啟動模式的介紹後,可能會覺得很困惑。官網介紹singleTask啟動模式時,說只要啟動singleTask啟動模式的Activity就會新建Task,但在實際操作中,如果同一個應用的兩個Activity,如果其中一個Activity的啟動模式為singleTask,一個Activity的啟動模式為standard,從其中一個Activity跳轉到另外一個Activity,並不會新建Task。
Application,Activity, Process,Thread之間的關系
我們知道在AndroidManifest.xml裡可聲明Application,它可以由4大組件組成:Activity,Service,ContentProvider,BroadcastReceiver。聲明Application時可以用android:name聲明本應用使用的Application類,如果沒有聲明,則會直接使用Android框架的Application類建立實例對象。
應用第一次啟動時,會啟動一個新進程,該進程用應用的包名作為進程名。該進程會啟動主線程ActivityThread,也叫做UI線程,UI的繪制都在該線程裡完成。該進程裡還有一些Binder服務線程,用於和系統進行通信。
另外,我們知道Activity跳轉時,可以跨應用跳轉,也就說應用app1裡的Activity A可以跳轉到應用app2裡的Activity B。如果Activity A和Activity B的啟動模式為standard模式,從A跳轉到B後,Activity A和Activity B對應的ActivityRecord會放在同一個task裡(ActivityRecord,Task都由系統進程管理,下一篇博客會介紹這些概念),但是Acitivity A和Activity B的實例對象會放在不同的進程裡。假設app1的包名為com.cloud.app1,app2的包名為com.cloud.app2,那麼Activity A的實例對象位於進程com.cloud.app1裡,Activity B的實例對象位於進程com.cloud.app2裡。
也就是說,每個應用的組件都會運行在對應的應用進程裡,該進程用應用的包名作為進程名。該進程裡有一個主線程,也叫做UI線程,應用組件都運行在UI線程裡。只有一種情況例外,如果聲明組件時用android:process設置了進程名,該組件就會運行在一個新進程裡,不是以應用的包名作為進程名,而是用包名+:+設置的值作為進程名
所以一般情況下service,receiver也會運行在ui線程裡,如果在service,receiver的生命周期方法裡做一些耗時的操作,系統會提示ANR(Activity Not Responde)錯誤。
Activity 啟動模式特點
Activity的啟動模式共有4種,默認為standard,其它還有singleTop,singleTask,singleInstance,下面就這4種啟動模式分別介紹它們的特點。
1) standard模式
standard模式的Activity可以有多個ActivityRecord加入不同的task,同一個task也可存在多個ActivityRecord,並且ActivityRecord還可相鄰。
假設Activity A的啟動模式為standard,那麼可能存在如下圖所示的回退棧:
假設Activity A啟動Activity B,B的啟動模式為standard模式
B的ActivityRecord默認會放在A的ActivityRecord所在的task裡,即使B和A的taskAffinity不同也會如此,這也意味著如果B和A屬於不同的應用,B的ActivityRecord也會放在A的ActivityRecord所在的task裡。
但是下面兩種情況不會將A和B的ActivityRecord放在同一個task裡:
如果Activity A的啟動模式為singleInstance,則會查找整個回退棧,直到找到和B相關的task,然後把B的ActivityRecord放到該task裡,如果沒有找到相關的task,則新建task,將B的ActivityRecord放到新task裡。後面會介紹如何判斷Activity和某個task相關。
如果Activity A的啟動模式為singleTask,並且Activity A和Activity B的taskAffinity不一樣,那麼也會查找整個回退棧,直到找到和B相關的task,然後把B的ActivityRecord放到該task裡。
2) singleTop模式
singleTop模式與standard模式比較相似,singleTop模式的Activity可以有多個ActivityRecord加入不同的task,同一個task也可存在多個ActivityRecord,但是同一個task的ActivityRecord不可以相鄰。
假設Activity A的啟動模式為singleTop,那麼如下圖所示的回退棧就是不合理的:
但是可存在如下圖所示的回退棧:
假設Activity A啟動了Activity B, 這時B在task的棧頂,B的啟動模式為singleTop模式。此時從其它Activity也跳轉至Activity B,並且啟動的task也是已啟動的A和B所在的task,或者A和 B所在的task本身就回退棧的棧頂,那麼不會新建B的ActivityRecord,而是會將啟動Activity B的Intent傳遞給棧頂Activity B的ActivityRecrod對應的在應用進程的實例對象,調用它的onNewIntent方法。
可以這樣模擬此種情況:
假設Activity A和Activity B在同一個應用app1裡,A是入口Activity,A可跳轉至Activity B,B的啟動模式為singleTop。此時已從A跳轉至B,通知欄有一個啟動B的通知,點擊通知後,就出現上述情況。
3) singleTask模式
singleTask模式和standard模式,singleTop模式區別很大,singleTask模式的Activity在整個回退棧只可以有一個ActivityRecord,也就是說它只能屬於某一個task,不可在多個task裡存在ActivityRecord。但是在這個task裡可以有其它Activity的ActivityRecord。
假設Activity A的啟動模式為singleTask,那麼如下圖所示的回退棧就是不合理的:
假設Activity A的啟動模式為singleTask,那麼如下圖所示的回退棧就是合理的:
假設Activity A的啟動模式為singleTask,那麼和Activity A的ActivityRecord放在同一個task裡的ActivityRecord所對應的Activity,必須與Activity A的taskAffinity相同。也就是說,Activity A的ActivityRecord只會和同一應用的其它Activity的ActivityRecord放在同一個task裡,並且這些同一應用的其它Activity不能設置特殊的taskAffinity。
singleTask模式的Activity還有另一個特點:
假設Activity A的啟動模式是singleTask,A所在的task裡,A並沒有處於棧頂,此時若從別的Activity跳轉至Activity A,那麼A所在的task裡位於A之上的所有ActivityRecord都會被清除掉。
跳轉之前回退棧的示意圖如下所示:
此時從E跳轉至A之後,回退棧的示意圖如下圖所示:
也就是說位A所在的task裡的C被清除了。
另外需注意:
只要兩個Activity的taskAffinity屬性一致,即使其中有一個Activity的啟動模式為singleTask,它們對應的ActivityRecord會放在同一個task裡,不管是從某個Activity跳轉到singleTask類型的Activity,還是從singleTask類型的Activity跳轉到其他Activity都是如此,除非跳轉的其他Activity的啟動模式是singleInstance。Android官方文檔對singleTask啟動模式的描述不准確。
舉例如下:
假設某個應用有兩個Activity A和Activity B,Activity A已啟動,Activity B的啟動模式為singleTask,Activity B還從未啟動過,在AndroidManifest.xml裡沒有給這兩個Activity設置特殊的taskAffinity。此時從Activity A跳轉至Activity B,那麼Activity B的ActivityRecord會放在Activity A的ActivityRecord所在的task裡。
4) singleInstance模式
該啟動模式和singleTask類似,singleInstance模式的Activity在整個回退棧只可以有一個ActivityRecord,也就是說它只能屬於某一個task,不可在多個task裡存在ActivityRecord,並且它所在的task不可再有其它Activity的ActivityRecord,即使是同一個應用內的其它Activity,也不可有它們的AcvitityRecord。
假設Activity A的啟動模式為singleInstance,那麼如下圖所示的回退棧就是不合理的:
假設Activity A的啟動模式為singleInstance,那麼如下圖所示的回退棧就是合理的:
啟動Activity時,有時需要查看回退棧,看是否有和這個Activity相關的task。Activity和某個task相關,有兩種情況(假設Activity為A,相關的task為task1):
1) 如果A的啟動模式為singleInstance,那麼task1只能包含1個ActivityRecord,並且ActivityRecord對應的Activity必須是A2) A的啟動模式不是singleInstance,A的taskAffinity屬性和task1的taskAffinity屬性必須一樣。Task的taskAffinity屬性由它包含的第1個ActivityRecord的taskAffinity屬性決定。
注意
1) 從Launcher程序啟動應用時,會先查找所有task,看是否有相關task,如果已有相關task,則會將相關task移動到回退棧的棧頂,然後顯示棧頂Activity。查找相關task時,需看task是否和應用的入口Activity相關,入口Activity是指在AndroidManifest.xml裡聲明IntentFilter時,注明category為android.intent.category.LAUNCHER的Activity。如果入口Activity的啟動模式為singleTask,不僅會將相關task移動到回退棧的棧頂,還會將該task裡位於入口Activity之上的其它ActivityRecord全部清除掉2) 通過最近應用程序,切換應用時,會直接將應用圖標對應的task移動到回退棧的棧頂,這樣即使task裡有singleTask類型的ActivityRecord,在它之上的ActivityRecord也不會被清除3) 可以通過adb shell dumpsys activity activties查看系統task情況
思考問題
1) 首次啟動應用,是否會產生新的task?2) 假設應用app1的入口Activity(Activity A)啟動模式為standard,從A可跳轉至Acitivity B,Activity B的啟動模式為singleTask,那麼啟動應用後,從ActivityA跳轉到ActivityB是否會產生新的task?3) 假設應用app1的入口Activity是A,從A可跳轉至B,從B可跳轉至C,B的啟動模式為singleTask,A和C的啟動模式為standard,Activity的跳轉順序為A->B->C是否會產生新的task? 如果C的啟動模式也為singleTask呢? 如果C的啟動模式為singleInstance呢?4) 假設應用app1的入口Activity是A,從A可跳轉至B, B的啟動模式為singleTask,A的啟動模式為standard,另一個應用app2有一個Activity C,C的啟動模式為stanard,C也可跳轉至B,目前已從A跳轉到B,此時再打開應用app2,從C跳轉至B,是否會產生新的task呢? 如果應用app1沒啟動,是否會產生新的task呢?5) 假設應用app1的入口Activity是A,從A可跳轉至B,從B可跳轉至C, B的啟動模式為singleTask,A,C的啟動模式為standard,從A跳轉至B後,A會finish,假設此時A已跳轉至B,B已跳轉至C,此時通知欄有一個通知,可啟動Activity B,那麼點擊通知後,會出現什麼情況呢?
效果圖思路首先我們來分析一下實現九宮格解鎖的思路:當用戶的手指觸摸到某一個點時,先判斷該點是否在九宮格的某一格范圍之內,若在范圍內,則該格變成選中的狀態;之後用戶手指滑動
ListView是一種非常常見的一個組件,以垂直列表的形式顯示列表項。而完成一個簡單的ListView只需要這麼三個步驟:1、在布局文件XML中添加ListView並配置
今天在做項目的時候用到了圖表功能,記錄下來achartengine是google的一個開源項目,可以在https://code.google.com/p/acharten
前段時間做了一個失敗的圖像處理項目,結果雖然不太好,也學到了不少東西,其中關於在Eclipse裡如何使用opencv的圖片處理api折騰了一陣子,記錄一下:1、Andro