android面試題之七(紅黑聯盟)

本文屬於轉載 原文地址http://www.2cto.com/kf/201309/246530.html


三十六、請解釋下在單線程模型中Message、Handler、Message Queue、Looper之間的關係。

 
簡單的說,Handler獲取當前線程中的looper對象,looper用來從存放Message的MessageQueue中取出Message,再有Handler進行Message的分發和處理.
 
Message Queue(消息隊列):用來存放通過Handler發佈的消息,通常附屬於某一個創建它的線程,可以通過Looper.myQueue()得到當前線程的消息隊列.
 
Handler:可以發佈或者處理一個消息或者操作一個Runnable,通過Handler發佈消息,消息將只會發送到與它關聯的消息隊列,然也只能處理該消息隊列中的消息.
 
Looper:是Handler和消息隊列之間通訊橋樑,程序組件首先通過Handler把消息傳遞給Looper,Looper把消息放入隊列。Looper也把消息隊列裏的消息廣播給所有的Handler:Handler接受到消息後調用handleMessage進行處理.
 
Message:消息的類型,在Handler類中的handleMessage方法中得到單個的消息進行處理,在單線程模型下,爲了線程通信問題,Android設計了一個Message Queue(消息隊列),線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:
 
1. Message
 
Message消息,理解爲線程間交流的信息,處理數據後臺線程需要更新UI,則發送Message內含一些數據給UI線程。
 
2. Handler
 
Handler處理者,是Message的主要處理者,負責Message的發送,Message內容的執行處理。後臺線程就是通過傳進來的 Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message)方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。
 
3. Message Queue
 
Message Queue消息隊列,用來存放通過Handler發佈的消息,按照先進先出執行。
 
每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被 Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。
 
4. Looper
 
Looper是每條線程裏的Message Queue的管家。Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程裏並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不爲NULL,但調用Looper.myLooper() 得到當前線程的Looper就有可能爲NULL。對於子線程使用Looper,API Doc提供了正確的使用方法:這個Message機制的大概流程:
 
1. 在Looper.loop()方法運行開始後,循環地按照接收順序取出Message Queue裏面的非NULL的Message。
 
2. 一開始Message Queue裏面的Message都是NULL的。當Handler.sendMessage(Message)到Message Queue,該函數裏面設置了那個Message對象的target屬性是當前的Handler對象。隨後Looper取出了那個Message,則調用該Message的target指向的Hander的dispatchMessage函數對Message進行處理。在dispatchMessage方法裏,如何處理Message則由用戶指定,三個判斷,優先級從高到低:
 
1) Message裏面的Callback,一個實現了Runnable接口的對象,其中run函數做處理工作;
 
2) Handler裏面的mCallback指向的一個實現了Callback接口的對象,由其handleMessage進行處理;
 
3) 處理消息Handler對象對應的類繼承並實現了其中handleMessage函數,通過這個實現的handleMessage函數處理消息。
 
由此可見,我們實現的handleMessage方法是優先級最低的!
 
3. Handler處理完該Message (update UI) 後,Looper則設置該Message爲NULL,以便回收!
 
在網上有很多文章講述主線程和其他子線程如何交互,傳送信息,最終誰來執行處理信息之類的,個人理解是最簡單的方法——判斷Handler對象裏面的Looper對象是屬於哪條線程的,則由該線程來執行!
 
1. 當Handler對象的構造函數的參數爲空,則爲當前所在線程的Looper;
 
2. Looper.getMainLooper()得到的是主線程的Looper對象,Looper.myLooper()得到的是當前線程的Looper對象。
 
 
 
三十七、activity的啓動模式有哪些?是什麼含義?
 
啓動模式有四種:standard(默認)、singleTop、singleTask、singleInstance。
 
對區分它們關鍵是在於理解它們各自的特點:
 
1、對於standard和singleTop可分爲一組:它們都可以多次實例化,可位於任意的棧中,被啓動者和啓動者位於同一task中(除非Intent的flags爲FLAG_ACTIVITY_NEW_TASK)。
 
區別(關鍵):singleTop:當前實例如果在棧頂,就不新建實例,調用其OnNewIntent。如不在棧頂,則新建實例。singleTop模式,可用來解決棧頂多個重複相同的Activity的問題。
 
2、對於singleTask和singleInstance:都是隻創建一個實例的。
 
區別(關鍵):某個activity的啓動模式設爲singleTask後,該棧中只能有一個該activity的實例,但可以有多個其他activity實例。而某個activity的啓動模式設爲singleInstance後,表示該activity所在棧只能有它一個實例,無論其他activity啓動模式是什麼,都不能與它共存。
 
結合示例便一目瞭然:http://blog.csdn.net/u010142437/article/details/12070059
 
 
 
三十八、跟activity和Task 有關的 Intent啓動方式有哪些?其含義?
 
核心的Intent Flag有:
 
FLAG_ACTIVITY_NEW_TASK
 
FLAG_ACTIVITY_CLEAR_TOP
 
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
 
FLAG_ACTIVITY_SINGLE_TOP
 
FLAG_ACTIVITY_NEW_TASK
 
如果設置,這個Activity會成爲歷史stack中一個新Task的開始。一個Task(從啓動它的Activity到下一個Task中的 Activity)定義了用戶可以遷移的Activity原子組。Task可以移動到前臺和後臺;在某個特定Task中的所有Activity總是保持相同的次序。
 
這個標誌一般用於呈現“啓動”類型的行爲:它們提供用戶一系列可以單獨完成的事情,與啓動它們的Activity完全無關。
 
使用這個標誌,如果正在啓動的Activity的Task已經在運行的話,那麼,新的Activity將不會啓動;代替的,當前Task會簡單的移入前臺。參考FLAG_ACTIVITY_MULTIPLE_TASK標誌,可以禁用這一行爲。
 
這個標誌不能用於調用方對已經啓動的Activity請求結果。
 
FLAG_ACTIVITY_CLEAR_TOP
如果設置,並且這個Activity已經在當前的Task中運行,因此,不再是重新啓動一個這個Activity的實例,而是在這個Activity上方的所有Activity都將關閉,然後這個Intent會作爲一個新的Intent投遞到老的Activity(現在位於頂端)中。
例如,假設一個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標誌,那麼它將關閉然後重新創建;對於其它的啓動模式,或者在這個Intent中設置FLAG_ACTIVITY_SINGLE_TOP標誌,都將把這個Intent投遞到當前這個實例的onNewIntent()中。
這個啓動模式還可以與FLAG_ACTIVITY_NEW_TASK結合起來使用:用於啓動一個Task中的根Activity,它會把那個Task中任何運行的實例帶入前臺,然後清除它直到根Activity。這非常有用,例如,當從Notification Manager處啓動一個Activity。
 
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
 
如果設置這個標誌,這個activity不管是從一個新的棧啓動還是從已有棧推到棧頂,它都將以the front door of the task的方式啓動。這就講導致任何與應用相關的棧都講重置到正常狀態(不管是正在講activity移入還是移除),如果需要,或者直接重置該棧爲初始狀態。
 
FLAG_ACTIVITY_SINGLE_TOP 
如果設置,當這個Activity位於歷史stack的頂端運行時,不再啓動一個新的
 
FLAG_ACTIVITY_BROUGHT_TO_FRONT 
這個標誌一般不是由程序代碼設置的,如在launchMode中設置singleTask模式時系統幫你設定。
 
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中觸發的操作。然而,當用戶離開這個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),並且這個結果值將發送給那個作爲答覆目標的 Activity。
 
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 
這個標誌一般不由應用程序代碼設置,如果這個Activity是從歷史記錄裏啓動的(常按HOME鍵),那麼,系統會幫你設定。
 
FLAG_ACTIVITY_MULTIPLE_TASK 
不要使用這個標誌,除非你自己實現了應用程序啓動器。與FLAG_ACTIVITY_NEW_TASK結合起來使用,可以禁用把已存的Task送入前臺的行爲。當設置時,新的Task總是會啓動來處理Intent,而不管這是是否已經有一個Task可以處理相同的事情。
由於默認的系統不包含圖形Task管理功能,因此,你不應該使用這個標誌,除非你提供給用戶一種方式可以返回到已經啓動的Task。
如果FLAG_ACTIVITY_NEW_TASK標誌沒有設置,這個標誌被忽略。
 
FLAG_ACTIVITY_NO_ANIMATION
如果在Intent中設置,並傳遞給Context.startActivity()的話,這個標誌將阻止系統進入下一個Activity時應用 Acitivity遷移動畫。這並不意味着動畫將永不運行——如果另一個Activity在啓動顯示之前,沒有指定這個標誌,那麼,動畫將被應用。這個標誌可以很好的用於執行一連串的操作,而動畫被看作是更高一級的事件的驅動。
 
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不認爲用戶已經知曉其Notification。
 
FLAG_ACTIVITY_PREVIOUS_IS_TOP 
If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately.
 
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在Intent中設置,並傳遞給Context.startActivity(),這個標誌將引發已經運行的Activity移動到歷史stack的頂端。
例如,假設一個Task由四個Activity組成:A,B,C,D。如果D調用startActivity()來啓動Activity B,那麼,B會移動到歷史stack的頂端,現在的次序變成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP標誌也設置的話,那麼這個標誌將被忽略。
 
 
 
三十九、ListView的優化方案
 
1、如果自定義適配器,那麼在getView方法中要考慮方法傳進來的參數contentView是否爲null,如果爲null就創建contentView並返回,如果不爲null則直接使用。在這個方法中儘可能少創建view。
2、給contentView設置tag(setTag()),傳入一個viewHolder對象,用於緩存要顯示的數據,可以達到圖像數據異步加載的效果。
3、如果listview需要顯示的item很多,就要考慮分頁加載。比如一共要顯示100條或者更多的時候,我們可以考慮先加載20條,等用戶拉到列表底部的時候再去加載接下來的20條。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章