該系列文章主要介紹android里基本組件的了解和使用
圣經(jīng)?該系列文章將以標簽的形式添加征椒,在以后的工作中也會不斷完善他匪,也希望有其他朋友補充,最終希望能讓閱讀的人通過一篇文章就能解決了解與這組件相關的大部分問題潜的,比如說第一篇Activity,除了常見的生命周期外字管,還會介紹activity的創(chuàng)建過程啰挪,啟動模式等等
中級?如果要把android工程師分初中高三個等級的話嘲叔,個人覺得應該達到以下要求
初級:能熟練使用android的view控件和activity亡呵,靈活得在前臺后臺線程進行切換,根據(jù)產品需求硫戈,完成ui層面的任務
中級:熟練使用android四大組件锰什,初步理解背后實現(xiàn)的機制和原理,理解事件分發(fā)三大關鍵函數(shù)dispatchTouchEven,onInterceptTouchEvent汁胆,onTouchEvent梭姓,能夠解決大部分父子節(jié)點事件傳遞的問題,理解NestedScroll(嵌套滑動接口)嫩码,熟悉view的繪制流程(onMeasure-》onLayout-》onDraw)及這三個函數(shù)在view和viewgroup之間的不同點糊昙,能熟練得自定義view。
高級:看過并理解view的源碼谢谦,對于自定義view之類的不再覺得是問題,研究理解優(yōu)秀的android框架萝衩,比如Fresco(圖片加載)回挽,Volley(網(wǎng)絡請求),需要時可以自己開發(fā)簡化版猩谊,游刃有余地處理內存的使用和回收千劈,處理不同線程的并發(fā)情況,能在項目中運用合適的開發(fā)模式牌捷。
希望通過這系列教程和自己的實踐墙牌,能讓大家達到中級的開發(fā)水平
Activity生命周期(地球人都知道),但你知不知道onPause和onStop的區(qū)別暗甥?為什么要存在兩個不同的回調喜滨?onDestory實際上做了什么?
當當前activity失去焦點時撤防,會馬上觸發(fā)onPause(比如跳轉到新的activitiy虽风,切到后臺),之后過一段時間后假如檢測改activity依然在后臺寄月,此時才會觸發(fā)onStop辜膝。
當新打開的Activity是Dialog風格時或者是透明時;這兩種情況只會調用onPause方法,但不會調用onStop方法。
銷毀activity時如果內存緊張漾肮,系統(tǒng)會直接結束這個Activity厂抖,而不會觸發(fā) onStop 方法。所以保存臨時數(shù)據(jù)的方法必須放在onPause做克懊,而不是onStop忱辅。
onDestroy實際上并沒有馬上把activity銷毀,而是把該activity從當前的activity棧中移除谭溉,大多數(shù) app并不需要實現(xiàn)這個方法耕蝉,因為局部類的references會隨著activity的銷毀而銷毀,但是加入這個時候你的activity被其他地方強引用(例如有個動畫不斷在執(zhí)行)夜只,這時候你會發(fā)現(xiàn)在即使onDestroy被調用垒在,但是改activity依然存在系統(tǒng)的內存中,所以單單依靠這個函數(shù)來回收資源是不夠的。
順便說一下Fragment的生命周期
Fragment是和activity綁定的场躯,但創(chuàng)建時首先會觸發(fā)onAttach谈为,此時可以獲取到context對象,
onAttach方法:Fragment和Activity建立關聯(lián)的時候調用踢关。
onCreateView方法:為Fragment加載布局時調用伞鲫。
onActivityCreated方法:當Activity中的onCreate方法執(zhí)行完后調用。
onDestroyView方法:Fragment中的布局被移除時調用签舞。
onDetach方法:Fragment和Activity解除關聯(lián)的時候調用秕脓。
activity為什么要細化出onCreate、onStart儒搭、onResume吠架、onPause、onStop搂鲫、onDesdroy?相信很多人為這個問題困擾很久傍药,先來看一個圖,從Activity A跳轉到Activity B的回調順序
可以發(fā)現(xiàn)跳轉發(fā)生時魂仍,先調用了A的onPause拐辽,之后等到B的onStart和onResume完成后才調用A的onStop,這樣設計的目的在于讓開發(fā)者可以在不同階段進行不同資源的釋放或者創(chuàng)建擦酌,舉個例子俱诸,先看下onResume的官方定義
void android.app.Activity.onResume()
Called after onRestoreInstanceState, onRestart, or onPause, for your activity to start interacting with the user. This is a good place to begin animations, open exclusive-access devices (such as the camera), etc.
Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged to know for certain that your activity is visible to the user (for example, to resume a game).
“open exclusive-access devices (such as the camera)",比如你的應用有打開camera的操作赊舶,假如camera的初始化你放到了onCreate里面乙埃,釋放放到了onStop或者onDestroy里面,假設A和B都需要camera的資源锯岖,那么當A跳轉到B時介袜,B在oncreate創(chuàng)建camera引用,就會出現(xiàn)A里面的camera還沒有釋放的問題出吹,所以google建議是在onResume()中打開獨占設備(比如相機)遇伞,在onpause里把這些資源釋放出去。
所有的初始化都在onCreate()中實現(xiàn)捶牢?
onCreate()代表activity被創(chuàng)建鸠珠,onStart代表該Activity變成可見狀態(tài),Activity的onCreate()被調用時秋麸,Activity還不可見渐排,如果要做一些動畫,既然視圖還不存在灸蟆,在onCreate中來啟動動畫驯耻,明顯有問題;
其次,A Activity 切換到 B Activity可缚,再切換到 A Activity霎迫,由于實例已經(jīng)存在,所以onCreate不會再被調用帘靡,那AActivity從后臺切換至前臺時知给,有可能需要一些初始化,那就沒法再被調用到了描姚;
所有的初始化都在onStart()中實現(xiàn)涩赢?
onStart() 被調用時,Activity可能是可見了轩勘,但還不是可交互的筒扒,onResume()的注釋中都明確地說了這不是Activity對用戶是可見的最好的指示器,onStart() 在這之前被調用赃阀,那有一些特殊的初始化相關的邏輯在這里被調用也會有問題。
這只是很簡單的例子擎颖,實際中要根據(jù)實際情況處理榛斯,總的來說可以把一些view的初始化工作放到onCreate里面,在onstart時可以開啟一些動畫事件搂捧,最后在onresume時才打開獨占設備驮俗,在onpause時把動畫停止,獨占設備的資源釋放出去允跑,停止網(wǎng)絡輪詢王凑,而不是onStop,最后看一下官方解釋:
void android.app.Activity.onStop()
Called when you are no longer visible to the user. You will next receive either onRestart, onDestroy, or nothing, depending on later user activity.
Note that this method may never be called, in low memory situations where the system does not have enough memory to keep your activity's process running after its onPause method is called.
onStop() 的注釋中明確地寫了聋丝,在內存不足而導致系統(tǒng)無法保留此進程的情況下索烹,onStop() 可能都不會被執(zhí)行。
Acitity啟動模式:
涉及關鍵詞“LaunchMode"弱睦,”Task stack“百姓,“intent”,由于intent我們之后還有一篇文章專門來講况木,所以主要看前面兩個垒拢。
LauchMode有四種,分別為standard火惊,singleTop求类,singleTask,singleInstance屹耐,可以在xml里面配置好尸疆,也可以在startactivity啟動時設定,后者優(yōu)先級高于前者。在這里先記錄一下官方的定義
"standard":Default. The system always creates a new instance of the activity in the target task and routes the intent to it.
"singleTop":If an instance of the activity already exists at the top of the target task, the system routes the intent to that instance through a call to itsonNewIntent()method, rather than creating a new instance of the activity.
"singleTask":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 itsonNewIntent()method, rather than creating a new one.
"singleInstance":Same as "singleTask", except that the system doesn't launch any other activities into the task holding the instance. The activity is always the single and only member of its task.
這里注意一點仓技,就是singleTop其實是并不一定保證唯一性的鸵贬,比如一個視頻播放的activity,當點擊home健退到后臺后脖捻,通過點擊notification到splash頁面再回來這個activity阔逼,其實已經(jīng)不是之前那一個了,已有的信息會被刪除掉地沮。這種情況可以考慮使用singletask
接著看一下startactivity時可以設置的flag有哪些:
FLAG_ACTIVITY_BROUGHT_TO_FRONT
這個標志一般不是由程序代碼設置的嗜浮,如在launchMode中設置singleTask模式時系統(tǒng)幫你設定。
FLAG_ACTIVITY_SINGLE_TOP
如果設置摩疑,當這個Activity位于歷史stack的頂端運行時危融,不再啟動一個新的。
FLAG_ACTIVITY_NEW_TASK
如果設置雷袋,這個Activity會成為歷史stack中一個新Task的開始吉殃。一個Task(從啟動它的Activity到下一個Task中的 Activity)定義了用戶可以遷移的Activity原子組。Task可以移動到前臺和后臺楷怒;在某個特定Task中的所有Activity總是保持相同的次序蛋勺。
這個標志一般用于呈現(xiàn)“啟動”類型的行為:它們提供用戶一系列可以單獨完成的事情,與啟動它們的Activity完全無關鸠删。
使用這個標志抱完,如果正在啟動的Activity的Task已經(jīng)在運行的話,那么刃泡,新的Activity將不會啟動巧娱;代替的,當前Task會簡單的移入前臺烘贴。參考FLAG_ACTIVITY_MULTIPLE_TASK標志禁添,可以禁用這一行為
這個標志不能用于調用方對已經(jīng)啟動的Activity請求結果。
FLAG_ACTIVITY_CLEAR_TOP(top的意思是指蓋在該activity上面桨踪,比他遲創(chuàng)建啟動的)
如果設置上荡,并且這個Activity已經(jīng)在當前的Task中運行,因此馒闷,不再是重新啟動一個這個Activity的實例酪捡,而是在這個Activity上方的所有Activity都將關閉,然后這個Intent會作為一個新的Intent投遞到老的Activity(現(xiàn)在位于頂端)中纳账。
例如逛薇,假設一個Task中包含這些Activity:A,B疏虫,C永罚,D啤呼。如果D調用了startActivity(),并且包含一個指向Activity B的Intent呢袱,那么官扣,C和D都將結束,然后B接收到這個Intent羞福,因此惕蹄,目前stack的狀況是:A,B治专。
上例中正在運行的Activity B既可以在onNewIntent()中接收到這個新的Intent卖陵,也可以把自己關閉然后重新啟動來接收這個Intent。如果它的啟動模式聲明為 “multiple”(默認值)张峰,并且你沒有在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標志泪蔫,那么它將關閉然后重新創(chuàng)建;對于其它的啟動模式喘批,或者在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標志撩荣,都將把這個Intent投遞到當前這個實例的onNewIntent()中。
這個啟動模式還可以與FLAG_ACTIVITY_NEW_TASK結合起來使用:用于啟動一個Task中的根Activity饶深,它會把那個Task中任何運行的實例帶入前臺餐曹,然后清除它直到根Activity。這非常有用粥喜,例如凸主,當從Notification Manager處啟動一個Activity橘券。
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果設置额湘,這將在Task的Activity stack中設置一個還原點,當Task恢復時旁舰,需要清理Activity锋华。也就是說,下一次Task帶著 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標記進入前臺時(典型的操作是用戶在主畫面重啟它)箭窜,這個Activity和它之上的都將關閉毯焕,以至于用戶不能再返回到它們,但是可以回到之前的Activity磺樱。
這在你的程序有分割點的時候很有用纳猫。例如,一個e-mail應用程序可能有一個操作是查看一個附件竹捉,需要啟動圖片瀏覽Activity來顯示芜辕。這個 Activity應該作為e-mail應用程序Task的一部分,因為這是用戶在這個Task中觸發(fā)的操作块差。然而侵续,當用戶離開這個Task倔丈,然后從主畫面選擇e-mail app,我們可能希望回到查看的會話中状蜗,但不是查看圖片附件需五,因為這讓人困惑。通過在啟動圖片瀏覽時設定這個標志轧坎,瀏覽及其它啟動的Activity在下次用戶返回到mail程序時都將全部清除宏邮。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果設置,新的Activity不會在最近啟動的Activity的列表中保存眶根。
FLAG_ACTIVITY_FORWARD_RESULT
如果設置蜀铲,并且這個Intent用于從一個存在的Activity啟動一個新的Activity,那么属百,這個作為答復目標的Activity將會傳到這個新的Activity中记劝。這種方式下,新的Activity可以調用setResult(int)族扰,并且這個結果值將發(fā)送給那個作為答復目標的 Activity厌丑。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
這個標志一般不由應用程序代碼設置,如果這個Activity是從歷史記錄里啟動的(常按HOME鍵)渔呵,那么怒竿,系統(tǒng)會幫你設定。
FLAG_ACTIVITY_MULTIPLE_TASK
不要使用這個標志扩氢,除非你自己實現(xiàn)了應用程序啟動器耕驰。與FLAG_ACTIVITY_NEW_TASK結合起來使用,可以禁用把已存的Task送入前臺的行為录豺。當設置時朦肘,新的Task總是會啟動來處理Intent,而不管這是是否已經(jīng)有一個Task可以處理相同的事情双饥。
由于默認的系統(tǒng)不包含圖形Task管理功能媒抠,因此,你不應該使用這個標志咏花,除非你提供給用戶一種方式可以返回到已經(jīng)啟動的Task趴生。
如果FLAG_ACTIVITY_NEW_TASK標志沒有設置,這個標志被忽略昏翰。
FLAG_ACTIVITY_NO_ANIMATION
如果在Intent中設置苍匆,并傳遞給Context.startActivity()的話,這個標志將阻止系統(tǒng)進入下一個Activity時應用 Acitivity遷移動畫棚菊。這并不意味著動畫將永不運行——如果另一個Activity在啟動顯示之前浸踩,沒有指定這個標志,那么窍株,動畫將被應用民轴。這個標志可以很好的用于執(zhí)行一連串的操作攻柠,而動畫被看作是更高一級的事件的驅動。
FLAG_ACTIVITY_NO_HISTORY
如果設置后裸,新的Activity將不再歷史stack中保留瑰钮。用戶一離開它,這個Activity就關閉了微驶。這也可以通過設置noHistory特性浪谴。
FLAG_ACTIVITY_NO_USER_ACTION
如果設置,作為新啟動的Activity進入前臺時因苹,這個標志將在Activity暫停之前阻止從最前方的Activity回調的onUserLeaveHint()苟耻。
典型的,一個Activity可以依賴這個回調指明顯式的用戶動作引起的Activity移出后臺扶檐。這個回調在Activity的生命周期中標記一個合適的點凶杖,并關閉一些Notification。
如果一個Activity通過非用戶驅動的事件款筑,如來電或鬧鐘智蝠,啟動的,這個標志也應該傳遞給Context.startActivity奈梳,保證暫停的Activity不認為用戶已經(jīng)知曉其Notification杈湾。
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在Intent中設置,并傳遞給Context.startActivity()攘须,這個標志將引發(fā)已經(jīng)運行的Activity移動到歷史stack的頂端漆撞。
例如,假設一個Task由四個Activity組成:A,B,C,D于宙。如果D調用startActivity()來啟動Activity B浮驳,那么,B會移動到歷史stack的頂端限煞,現(xiàn)在的次序變成A,C,D,B抹恳。如果FLAG_ACTIVITY_CLEAR_TOP標志也設置的話员凝,那么這個標志將被忽略署驻。
Activity是運行在『所需的任務棧』健霹,什么是Activity所需的任務棧旺上?這里就要提一個參數(shù):TaskAffinity。這個參數(shù)標識了一個Activity所需的任務棧的名字糖埋,默認情況下所有的Activity所需的任務棧都是當前包名宣吱,當然我們也可以為每個Activity單獨指定TaskAffinity,注意這個屬性值必須不能和包名相同瞳别,TaskAffinity主要和singleTask配合使用征候,否則的話沒什么意義杭攻。當啟動一個被TaskAffinity標識了的Activity,那么該Activity就會運行在和TaskAffinity相同的任務棧中