android任務隊列
① android 線程執行完會主動銷毀嗎
不會自動銷毀,除非主動關閉它們。
一、銷毀的方法
1、通過線程
Hanlder是線程與Activity通信的橋梁,利用handler接收到任務線程,放到任務隊列裡面派對執行。
//調用該任務線程的run() 方法執行任務線程。
Handler updateBarHandler =new handler();
handler.post(Runnable Thread);
//移除handler里的任務線程,調用線程的stop()方法,銷毀線程。
handler.removecallbacks(Runnable Thread);
2、通過Timer
通過以下四種方法終止一個timer線程:
a)調用timer的cancle方法。可以從程序的任何地方調用此方法,甚至在一個timer task的run方法里;
b)讓timer線程成為一個daemon線程(可以在創建timer時使用new Timer(true)達到這個目地),這樣當程序只有daemon線程的時候,它就會自動終止運行;
c)當timer相關的所有task執行完畢以後,刪除所有此timer對象的引用(置成null),這樣timer線程也會終止;
d)調用System.exit方法,使整個程序(所有線程)終止。
② android怎麼實現任務隊列
主要就是有一個線程隊列,維護這些任務,這里沒有用到Queue而是用List是考慮到顯示的問題。
③ 請簡述什麼是android事件處理,並分析兩種android事件處理機制的實現過程和區別
UI編程通常都會伴隨事件處理,Android也不例外,它提供了兩種方式的事件處理:基於回調的事件處理和基於監聽器的事件處理。
對於基於監聽器的事件處理而言,主要就是為Android界面組件綁定特定的事件監聽器;對於基於回調的事件處理而言,主要做法是重寫Android組件特定的回調函數,Android大部分界面組件都提供了事件響應的回調函數,我們主要重寫它們就行。
一 基於監聽器的事件處理
相比於基於回調的事件處理,這是更具「面向對象」性質的事件處理方式。在監聽器模型中,主要涉及三類對象:
1)事件源Event Source:產生事件的來源,通常是各種組件,如按鈕,窗口等。
2)事件Event:事件封裝了界面組件上發生的特定事件的具體信息,如果監聽器需要獲取界面組件上所發生事件的相關信息,一般通過事件Event對象來傳遞。
3)事件監聽器Event Listener:負責監聽事件源發生的事件,並對不同的事件做相應的處理。
基於監聽器的事件處理機制是一種委派式Delegation的事件處理方式,事件源將整個事件委託給事件監聽器,由監聽器對事件進行響應處理。這種處理方式將事件源和事件監聽器分離,有利於提供程序的可維護性。
舉例:
View類中的OnLongClickListener監聽器定義如下:(不需要傳遞事件)
[java] view plainprint?
public interface OnLongClickListener {
boolean onLongClick(View v);
}
public interface OnLongClickListener {
boolean onLongClick(View v);
}
View類中的OnLongClickListener監聽器定義如下:(需要傳遞事件MotionEvent)
[java] view plainprint?
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
二 基於回調的事件處理
相比基於監聽器的事件處理模型,基於回調的事件處理模型要簡單些,該模型中,事件源和事件監聽器是合一的,也就是說沒有獨立的事件監聽器存在。當用戶在GUI組件上觸發某事件時,由該組件自身特定的函數負責處理該事件。通常通過重寫Override組件類的事件處理函數實現事件的處理。
舉例:
View類實現了KeyEvent.Callback介面中的一系列回調函數,因此,基於回調的事件處理機制通過自定義View來實現,自定義View時重寫這些事件處理方法即可。
[java] view plainprint?
public interface Callback {
// 幾乎所有基於回調的事件處理函數都會返回一個boolean類型值,該返回值用於
// 標識該處理函數是否能完全處理該事件
// 返回true,表明該函數已完全處理該事件,該事件不會傳播出去
// 返回false,表明該函數未完全處理該事件,該事件會傳播出去
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
public interface Callback {
// 幾乎所有基於回調的事件處理函數都會返回一個boolean類型值,該返回值用於
// 標識該處理函數是否能完全處理該事件
// 返回true,表明該函數已完全處理該事件,該事件不會傳播出去
// 返回false,表明該函數未完全處理該事件,該事件會傳播出去
boolean onKeyDown(int keyCode, KeyEvent event);
boolean onKeyLongPress(int keyCode, KeyEvent event);
boolean onKeyUp(int keyCode, KeyEvent event);
boolean onKeyMultiple(int keyCode, int count, KeyEvent event);
}
三 比對
基於監聽器的事件模型符合單一職責原則,事件源和事件監聽器分開實現;
Android的事件處理機制保證基於監聽器的事件處理會優先於基於回調的事件處理被觸發;
某些特定情況下,基於回調的事件處理機制會更好的提高程序的內聚性。
四 基於自定義監聽器的事件處理流程
在實際項目開發中,我們經常需要自定義監聽器來實現自定義業務流程的處理,而且一般都不是基於GUI界面作為事件源的。這里以常見的app自動更新為例進行說明,在自動更新過程中,會存在兩個狀態:下載中和下載完成,而我們的程序需要在這兩個狀態做不同的事情,「下載中」需要在UI界面上實時顯示軟體包下載的進度,「下載完成」後,取消進度條的顯示。這里進行一個模擬,重點在說明自定義監聽器的事件處理流程。
4.1)定義事件監聽器如下:
④ android開發中的handler隊列的疑問。
就是多線程,如果你在一個ui里做很多事情,這些事情都在ui的線程里執行,會顯得很卡,讓ui只做顯示,一些數據的處理交給另外一個線程會提高ui的顯示,不會造成主線程堵塞,要知道在界面里ui線程才是主線程
⑤ android中主線程會創建消息隊列嗎
一、Handler的定義: Handler主要接收子線程發送的數據, 並用此數據配合主線程更新UI,用來跟UI主線程交互用。比如可以用handler發送一個message,然後在handler的線程中來接收、處理該消息,以避免直接在UI主線程中處理事務導致影響UI主線程的其他處理工作,Android提供了Handler作為主線程和子線程的紐帶;也可以將handler對象傳給其他進程,以便在其他進程中通過handler給你發送事件;還可以通過handler的延時發送message,可以延時處理一些事務的處理。 通常情況下,當應用程序啟動時,Android首先會開啟一個主線程 (也就是UI線程) , 主線程為管理界面中的UI控制項,進行事件分發。如果此時需要一個耗時的操作,例如:聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象,如果5秒鍾還沒有完成的話,會收到Android系統的一個錯誤提示"強制關閉". 這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,但是當子線程中有涉及到操作UI的操作時,就會對主線程產生危險,也就是說,更新UI只能在主線程中更新,在子線程中操作是危險的. 這個時候,Handler就出現了來解決這個復雜的問題,由於Handler運行在主線程中(UI線程中),它與子線程可以通過Message對象來傳遞數據,這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳遞)Message對象,(裡麵包含數據), 把這些消息放入主線程隊列中,配合主線程進行更新UI。 二、Handler一些特點 handler可以分發Message對象和Runnable對象到主線程中, 每個Handler實例,都會綁定到創建他的線程中(一般是位於主線程), 也就是說Handler對象初始化後,就默認與對它初始化的進程的消息隊列綁定,因此可以利用Handler所包含的消息隊列,制定一些操作的順序。 三、Handler中分發消息的一些方法 post(Runnable) postAtTime(Runnable,long) postDelayed(Runnable long) post類方法允許你排列一個Runnable對象到主線程隊列中 sendEmptyMessage(int) sendMessage(Message) sendMessageAtTime(Message,long) sendMessageDelayed(Message,long) sendMessage類方法, 允許你安排一個帶數據的Message對象到隊列中,等待更新. 四、應用實例: 1,傳遞Message。用於接受子線程發送的數據, 並用此數據配合主線程更新UI。 在Android中,對於UI的操作通常需要放在主線程中進行操作。如果在子線程中有關於UI的操作,那麼就需要把數據消息作為一個Message對象發送到消息隊列中,然後,用Handler中的handlerMessge方法處理傳過來的數據信息,並操作UI。類sendMessage(Message msg)方法實現發送消息的操作。 在初始化Handler對象時重寫的handleMessage方法來接收Messgae並進行相關操作。 2,傳遞Runnable對象。用於通過Handler綁定的消息隊列,安排不同操作的執行順序。 Handler對象在進行初始化的時候,會默認的自動綁定消息隊列。利用類post方法,可以將Runnable對象發送到消息隊列中,按照隊列的機制按順序執行不同的Runnable對象中的run方法。 另外,Android的CPU分配的最小單元是線程,Handler一般是在某個線程里創建的,因而Handler和Thread就是相互綁定的,一一對應。而Runnable是一個介面,Thread是Runnable的子類。所以說,他倆都算一個進程。 視頻教程中的例子: 1. public class HandlerActivity extends Activity { 2. 3. //聲明兩個按鈕控制項 4. private Button startButton = null; 5. private Button endButton = null; 6. @Override 7. public void onCreate(Bundle savedInstanceState) { 8. super.onCreate(savedInstanceState); 9. setContentView(R.layout.main); 10. //根據控制項的ID得到代表控制項的對象,並為這兩個按鈕設置相應的監聽器 11. startButton = (Button)findViewById(R.id.startButton); 12. startButton.setOnClickListener(new StartButtonListener()); 13. endButton = (Button)findViewById(R.id.endButton); 14. endButton.setOnClickListener(new EndButtonListener()); 15. 16. } 17. class StartButtonListener implements OnClickListener{ 18. 19. @Override 20. public void onClick(View v) { 21. //調用Handler的post方法,將要執行的線程對象添加到隊列當中 22. handler.post(updateThread); 23. } 24. 25. } 26. 27. class EndButtonListener implements OnClickListener{ 28. 29. @Override 30. public void onClick(View v) { 31. handler.removeCallbacks(updateThread); 32. } 33. 34. } 35. //創建一個Handler對象 36. Handler handler = new Handler(); 37. //將要執行的操作寫在線程對象的run方法當中 38. Runnable updateThread = new Runnable(){ 39. 40. @Override 41. public void run() { 42. System.out.println("UpdateThread"); 43. //在run方法內部,執行postDelayed或者是post方法 44. handler.postDelayed(updateThread, 3000); 45. } 46. 47. }; 48. } 程序的運行結果就是每隔3秒鍾,就會在控制台列印一行UpdateTread。這是因為實現了Runnable介面的updateThread對象進入了空的消息隊列即被立即執行run方法,而在run方法的內部,又在3000ms之後將其再次發送進入消息隊列中。 3, Handler和多線程 post方法雖然發送的是一個實現了Runnable介面的類對象,但是它並非創建了一個新線程,而是執行了該對象中的run方法。也就是說,整個run中的操作和主線程處於同一個線程。 這樣對於那些簡單的操作,似乎並不會影響。但是對於耗時較長的操作,就會出現「假死」。為了解決這個問題,就需要使得handler綁定到一個新開啟線程的消息隊列上,在這個處於另外線程的上的消息隊列中處理傳過來的Runnable對象和消息。 1. public class HandlerTest2 extends Activity { 2. 3. @Override 4. protected void onCreate(Bundle savedInstanceState) { 5. // TODO Auto-generated method stub 6. super.onCreate(savedInstanceState); 7. setContentView(R.layout.main); 8. //列印了當前線程的ID 9. System.out.println("Activity-->" + Thread.currentThread().getId()); 10. //生成一個HandlerThread對象 11. HandlerThread handlerThread = new HandlerThread("handler_thread"); 12. //在使用HandlerThread的getLooper()方法之前,必須先調用該類的start(),同時開啟一個新線程; 13. handlerThread.start(); 14. //將由HandlerThread獲取的Looper傳遞給Handler對象,即由處於另外線程的Looper代替handler初始化時默認綁定的消息隊列來處理消息。 15. // HandlerThread顧名思義就是可以處理消息循環的線程,它是一個擁有Looper的線程 16. ,可以處理消息循環; 其實與其說Handler和一個線程綁定,倒不如說Handler和Looper是 17. 一一對應的。 18. MyHandler myHandler = new MyHandler(handlerThread.getLooper()); 19. Message msg = myHandler.obtainMessage(); 20. //將msg發送到目標對象,所謂的目標對象,就是生成該msg對象的handler對象 21. Bundle b = new Bundle(); 22. b.putInt("age", 20); 23. b.putString("name", "Jhon"); 24. msg.setData(b); 25. msg.sendToTarget(); //將msg發送到myHandler 26. } 27. 28. //定義類 29. class MyHandler extends Handler{ 30. public MyHandler(){ 31. 32. } 33. 34. public MyHandler(Looper looper){ 35. super(looper); 36. } 37. @Override 38. public void handleMessage(Message msg) { 39. Bundle b = msg.getData(); 40. int age = b.getInt("age"); 41. String name = b.getString("name"); 42. System.out.println("age is " + age + ", name is" + name); 43. System.out.println("Handler--->" + Thread.currentThread().getId()); 44. System.out.println("handlerMessage"); 45. } 46. } 47. } 這樣,當使用sendMessage方法傳遞消息或者使用post方法傳遞Runnable對象時,就會把它們傳遞到與handler對象綁定的處於另外一個線程的消息隊列中,它們將在另外的消息隊列中被處理。而主線程還會在發送操作完成時候繼續進行,不會影響當前的操作。 這里需要注意,這里用到的多線程並非由Runnable對象開啟的,而是ThreadHandler對象開啟的。Runnable對象只是作為一個封裝了操作的對象被傳遞,並未產生新線程。 另外再強調一遍,在UI線程(主線程)中: mHandler=new Handler(); mHandler.post(new Runnable(){ void run(){ //執行代碼.. } }); 這個線程其實是在UI線程之內運行的,並沒有新建線程。 常見的新建線程的方法是: Thread thread = new Thread(); thread.start(); HandlerThread thread = new HandlerThread("string"); thread.start();
⑥ Android多線程的四種方式:Handler、AsyncTask、ThreadPoolExector、IntentService
非同步通信機制,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實現 工作線程對UI的更新處理,最終實現非同步消息的處理。Handler不僅僅能將子線程的數據傳遞給主線程,它能實現任意兩個線程的數據傳遞。
(1)Message
Message 可以在線程之間傳遞消息。可以在它的內部攜帶少量數據,用於在不同線程之間進行數據交換。除了 what 欄位,還可以使用 arg1 和 arg2 來攜帶整型數據,使用 obj 來攜帶 Object 數據。
(2) Handler
Handler 作為處理中心,用於發送(sendMessage 系列方法)與處理消息(handleMessage 方法)。
(3) MessageQueue
MessageQueue 用於存放所有通過 Handler 發送的消息。這部分消息會一直存放在消息隊列中,直到被處理。每個線程中只會有一個 MessageQueue 對象
(4) Looper
Looper 用於管理 MessageQueue 隊列,Looper對象通過loop()方法開啟了一個死循環——for (;;){},不斷地從looper內的MessageQueue中取出Message,並傳遞到 Handler 的 handleMessage() 方法中。每個線程中只會有一個 Looper 對象。
AsyncTask 是一種輕量級的任務非同步類,可以在後檯子線程執行任務,且將執行進度及執行結果傳遞給 UI 線程。
(1)onPreExecute()
在 UI 線程上工作,在任務執行 doInBackground() 之前調用。此步驟通常用於設置任務,例如在用戶界面中顯示進度條。
(2)doInBackground(Params... params)
在子線程中工作,在 onPreExecute() 方法結束後執行,這一步被用於在後台執行長時間的任務,Params 參數通過 execute(Params) 方法被傳遞到此方法中。任務執行結束後,將結果傳遞給 onPostExecute(Result) 方法,同時我們可以通過 publishProgress(Progress) 方法,將執行進度發送給 onProgressUpdate(Progress) 方法。
(3)onProgressUpdate(Progress... values)
在 UI 線程上工作,會在 doInBackground() 中調用 publishProgress(Progress) 方法後執行,此方法用於在後台計算仍在執行時(也就是 doInBackgound() 還在執行時)將計算執行進度通過 UI 顯示出來。例如,可以通過動畫進度條或顯示文本欄位中的日誌,從而方便用戶知道後台任務執行的進度。
(4)onPostExecute(Result result)
在 UI 線程上工作,在任務執行完畢(即 doInBackground(Result) 執行完畢)並將執行結果傳過來的時候工作。
使用規則:
(1)AsyncTask 是個抽象類,所以要創建它的子類實現抽象方法
(1)AsyncTask 類必須是在 UI 線程中被載入,但在Android 4.1(API 16)開始,就能被自動載入完成。
(2)AsyncTask 類的實例對象必須在 UI 線程中被創建。
(3)execute() 方法必須是在 UI 線程中被調用。
(4)不要手動調用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()
(5)任務只能執行一次(如果嘗試第二次執行,將拋出異常)。即一個AsyncTask對象只能調用一次execute()方法。
原理:
其源碼中原理還是 Thread 與 Handler 的實現,其包含 兩個線程池,一個 Handler,如下所示:
名稱類型作用
SERIAL_EXECUTOR線程池分發任務,串列分發,一次只分發一個任務
THREAD_POOL_EXECUTOR線程池執行任務,並行執行,執行的任務由 SERIAL_EXECUTOR 分發
InternalHandlerHandler負責子線程與主線程的溝通,通知主線程做 UI 工作
一方面減少了每個並行任務獨自建立線程的開銷,另一方面可以管理多個並發線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務的執行。Executors利用工廠模式對ThreadPoolExecutor進行了封裝。
Executors提供了四種創建ExecutorService的方法,他們的使用場景如下:
1. Executors.newFixedThreadPool()
創建一個定長的線程池,每提交一個任務就創建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化。
當線程處於空閑狀態時,它們並不會被回收,除非線程池被關閉。當所有的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閑出來。
只有核心線程並且不會被回收,能夠更加快速的響應外界的請求。
2. Executors.newCachedThreadPool()
創建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活的回收空閑的線程,當需要增加時,它可以靈活的添加新的線程,而不會對池的長度作任何限制
線程數量不定的線程池,只有非核心線程,最大線程數為 Integer.MAX_VALUE。當線程池中的線程都處於活動狀態時,線程池會創建新的線程來處理新任務,否則利用空閑的線程來處理新任務。線程池中的空閑線程具有超時機制,為 60s。
任務隊列相當於一個空集合,導致任何任務都會立即被執行,適合執行大量耗時較少的任務。當整個線程池都處於限制狀態時,線程池中的線程都會超時而被停止。
3. Executors.newScheledThreadPool()
創建一個定長的線程池,而且支持定時的以及周期性的任務執行,類似於Timer。
非核心線程數沒有限制,並且非核心線程閑置的時候立即回收,主要用於執行定時任務和具有固定周期的重復任務。
4. Executors.newSingleThreadExecutor()
創建一個單線程化的executor,它只創建唯一的worker線程來執行任務
只有一個核心線程,保證所有的任務都在一個線程中順序執行,意義在於不需要處理線程同步的問題。
一般用於執行後台耗時任務,當任務執行完成會自動停止;同時由於它是一個服務,優先順序要遠遠高於線程,更不容易被系統殺死,因此比較適合執行一些高優先順序的後台任務。
使用步驟:創建IntentService的子類,重寫onHandleIntent方法,在onHandleIntent中執行耗時任務
原理:在源碼實現上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結束後會調用IntentService的stopSelf(int startId)方法嘗試停止服務。
IntentService的內部是通過消息的方式請求HandlerThread執行任務,HandlerThread內部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執行後台任務的
(HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個工作線程(非UI線程)+任務的等待隊列的形式,優點是不會有堵塞,減少了對性能的消耗,缺點是不能同時進行多個任務的處理,需要等待進行處理。處理效率低,可以當成一個輕量級的線程池來用)
⑦ android 網路請求為什麼要使用隊列
Toast必須出現在主線程上。您可以使用 new Handler(Looper.getMainLooper()) 來生成一個主線程 handler 從任何後台線程,然後使用它發布 toast 主線程的工作。 代碼像這會適合您: public static void backgroundThreadShortToast(final Context context, final String msg) { if (context != null && msg != null) { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); } }); } }
⑧ Android 重學系列 View的繪制流程(六) 硬體渲染(上)
本文開始聊聊Android中的硬體渲染。如果跟著我的文章順序,從SF進程到App進程的繪制流程一直閱讀,我們到這里已經有了一定的基礎,可以試著進行橫向比對如Chrome瀏覽器渲染流程,看看軟體渲染,硬體渲染,SF合成都做了什麼程度的優化。
先讓我們回顧一下負責硬體渲染的主體對象ThreadedRenderer在整個繪制流程中做了哪幾個步驟。
在硬體渲染的過程中,有一個很核心的對象RenderNode,作為每一個View繪制的節點對象。
當每一次進行准備進行繪制的時候,都會雷打不動執行如下三個步驟:
如果遇到什麼問題歡迎來到 https://www.jianshu.com/p/c84bfa909810 下進行討論
實際上整個硬體渲染的設計還是比較龐大。因此本文先聊聊ThreadedRender整個體系中主要對象的構造以及相關的原理。
首先來認識下面幾個重要的對象有一個大體的印象。
在Java層中面向Framework中,只有這么多,下面是一一映射的簡圖。
能看到實際上RenderNode也會跟著View 樹的構建同時一起構建整個顯示層級。也是因此ThreadedRender也能以RenderNode為線索構建出一套和軟體渲染一樣的渲染流程。
僅僅這樣?如果只是這么簡單,知道我習慣的都知道,我喜歡把相關總結寫在最後。如果把總攬寫在正文開頭是因為設計比較繁多。因為我們如果以流水線的形式進行剖析容易造成迷失細節的困境。
讓我繼續介紹一下,在硬體渲染中native層的核心對象。
如下是一個思維導圖:
有這么一個大體印象後,就不容易迷失在源碼中。我們先來把這些對象的實例化以及上面列舉的ThreadedRenderer在ViewRootImpl中執行行為的順序和大家來聊聊其原理,先來看看ThreadedRenderer的實例化。
當發現mSurfaceHolder為空的時候會調用如下函數:
而這個方法則調用如下的方法對ThreadedRenderer進行創建:
文件:/ frameworks / base / core / java / android / view / ThreadedRenderer.java
能不能創建的了ThreadedRenderer則決定於全局配置。如果ro.kernel.qemu的配置為0,說明支持OpenGL 則可以直接返回true。如果qemu.gles為-1說明不支持OpenGL es返回false,只能使用軟體渲染。如果設置了qemu.gles並大於0,才能打開硬體渲染。
我們能看到ThreadedRenderer在初始化,做了三件事情:
關鍵是看1-3點中ThreadRenderer都做了什麼。
文件:/ frameworks / base / core / jni / android_view_ThreadedRenderer.cpp
能看到這里是直接實例化一個RootRenderNode對象,並把指針的地址直接返回。
能看到RootRenderNode繼承了RenderNode對象,並且保存一個JavaVM也就是我們所說的Java虛擬機對象,一個java進程全局只有一個。同時通過getForThread方法,獲取ThreadLocal中的Looper對象。這里實際上拿的就是UI線程的Looper。
在這個構造函數有一個mDisplayList十分重要,記住之後會頻繁出現。接著來看看RenderNode的頭文件:
文件:/ frameworks / base / libs / hwui / RenderNode.h
實際上我把幾個重要的對象留下來:
文件:/ frameworks / base / core / java / android / view / RenderNode.java
能看到很簡單,就是包裹一個native層的RenderNode返回一個Java層對應的對象開放Java層的操作API。
能看到這個過程生成了兩個對象:
這個對象實際上讓RenderProxy持有一個創建動畫上下文的工廠。RenderProxy可以通過ContextFactoryImpl為每一個RenderNode創建一個動畫執行對象的上下文AnimationContextBridge。
文件:/ frameworks / base / libs / hwui / renderthread / RenderProxy.cpp
在這里有幾個十分重要的對象被實例化,當然這幾個對象在聊TextureView有聊過( SurfaceView和TextureView 源碼淺析 ):
我們依次看看他們初始化都做了什麼。
文件:/ frameworks / base / libs / hwui / renderthread / RenderThread.cpp
能看到其實就是簡單的調用RenderThread的構造函數進行實例化,並且返回對象的指針。
RenderThread是一個線程對象。先來看看其頭文件繼承的對象:
文件:/ frameworks / base / libs / hwui / renderthread / RenderThread.h
其中RenderThread的中進行排隊處理的任務隊列實際上是來自ThreadBase的WorkQueue對象。
文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h
ThreadBase則是繼承於Thread對象。當調用start方法時候其實就是調用Thread的run方法啟動線程。
另一個更加關鍵的對象,就是實例化一個Looper對象到WorkQueue中。而直接實例化Looper實際上就是新建一個Looper。但是這個Looper並沒有獲取當先線程的Looper,這個Looper做什麼的呢?下文就會揭曉。
WorkQueue把一個Looper的方法指針設置到其中,其作用可能是完成了某一件任務後喚醒Looper繼續工作。
而start方法會啟動Thread的run方法。而run方法最終會走到threadLoop方法中,至於是怎麼走進來的,之後有機會會解剖虛擬機的源碼線程篇章進行講解。
在threadloop中關鍵的步驟有如下四個:
在這個過程中創建了幾個核心對象:
另一個核心的方法就是,這個方法為WorkQueue的Looper注冊了監聽:
能看到在這個Looper中注冊了對DisplayEventReceiver的監聽,也就是Vsync信號的監聽,回調方法為displayEventReceiverCallback。
我們暫時先對RenderThread的方法探索到這里,我們稍後繼續看看回調後的邏輯。
文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h
能看到這里的邏輯很簡單實際上就是調用Looper的pollOnce方法,阻塞Looper中的循環,直到Vsync的信號到來才會繼續往下執行。詳細的可以閱讀我寫的 Handler與相關系統調用的剖析 系列文章。
文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h
實際上調用的是WorkQueue的process方法。
文件:/ frameworks / base / libs / hwui / thread / WorkQueue.h
能看到這個過程中很簡單,幾乎和Message的loop的邏輯一致。如果Looper的阻塞打開了,則首先找到預計執行時間比當前時刻都大的WorkItem。並且從mWorkQueue移除,最後添加到toProcess中,並且執行每一個WorkItem的work方法。而每一個WorkItem其實就是通過從某一個壓入方法添加到mWorkQueue中。
到這里,我們就明白了RenderThread中是如何消費渲染任務的。那麼這些渲染任務又是哪裡誕生呢?
上文聊到了在RenderThread中的Looper會監聽Vsync信號,當信號回調後將會執行下面的回調。
能看到這個方法的核心實際上就是調用drainDisplayEventQueue方法,對ui渲染任務隊列進行處理。
能到在這里mVsyncRequested設置為false,且mFrameCallbackTaskPending將會設置為true,並且調用queue的postAt的方法執行ui渲染方法。
還記得queue實際是是指WorkQueue,而WorkQueue的postAt方法實際實現如下:
/ frameworks / base / libs / hwui / thread / WorkQueue.h
情景帶入,當一個Vsync信號達到Looper的監聽者,此時就會通過WorkQueue的drainDisplayEventQueue 壓入一個任務到隊列中。
每一個默認的任務都是執行dispatchFrameCallback方法。這里的判斷mWorkQueue中是否存在比當前時間更遲的時刻,並返回這個WorkItem。如果這個對象在頭部needsWakeup為true,說明可以進行喚醒了。而mWakeFunc這個方法指針就是上面傳下來:
把阻塞的Looper喚醒。當喚醒後就繼續執行WorkQueue的process方法。也就是執行dispatchFrameCallbacks方法。
在這里執行了兩個事情:
先添加到集合中,在上面提到過的threadLoop中,會執行如下邏輯:
如果大小不為0,則的把中的IFrameCallback全部遷移到mFrameCallbacks中。
而這個方法什麼時候調用呢?稍後就會介紹。其實這部分的邏輯在TextureView的解析中提到過。
接下來將會初始化一個重要對象:
這個對象名字叫做畫布的上下文,具體是什麼上下文呢?我們現在就來看看其實例化方法。
文件:/ frameworks / base / libs / hwui / renderthread / CanvasContext.cpp
文件:/ device / generic / goldfish / init.ranchu.rc
在init.rc中默認是opengl,那麼我們就來看看下面的邏輯:
首先實例化一個OpenGLPipeline管道,接著OpenGLPipeline作為參數實例化CanvasContext。
文件:/ frameworks / base / libs / hwui / renderthread / OpenGLPipeline.cpp
能看到在OpenGLPipeline中,實際上就是存儲了RenderThread對象,以及RenderThread中的mEglManager。透過OpenGLPipeline來控制mEglManager進而進一步操作OpenGL。
做了如下操作:
文件:/ frameworks / base / libs / hwui / renderstate / RenderState.cpp
文件:/ frameworks / base / libs / hwui / renderthread / DrawFrameTask.cpp
實際上就是保存這三對象RenderThread;CanvasContext;RenderNode。
文件:/ frameworks / base / core / jni / android_view_ThreadedRenderer.cpp
能看到實際上就是調用RenderProxy的setName方法給當前硬體渲染對象設置名字。
文件:/ frameworks / base / libs / hwui / renderthread / RenderProxy.cpp
能看到在setName方法中,實際上就是調用RenderThread的WorkQueue,把一個任務隊列設置進去,並且調用runSync執行。
能看到這個方法實際上也是調用post執行排隊執行任務,不同的是,這里使用了線程的Future方式,阻塞了執行,等待CanvasContext的setName工作完畢。
⑨ android 主進程銷毀了,線程會不會也銷毀
不會自動銷毀,除非主動關閉它們。
一、銷毀的方法
1、通過線程
Hanlder是線程與Activity通信的橋梁,利用handler接收到任務線程,放到任務隊列裡面派對執行。
//調用該任務線程的run() 方法執行任務線程。
Handler updateBarHandler =new handler();
handler.post(Runnable Thread);
//移除handler里的任務線程,調用線程的stop()方法,銷毀線程。
handler.removecallbacks(Runnable Thread);
2、通過Timer
通過以下四種方法終止一個timer線程:
a)調用timer的cancle方法。可以從程序的任何地方調用此方法,甚至在一個timer task的run方法里;
b)讓timer線程成為一個daemon線程(可以在創建timer時使用new Timer(true)達到這個目地),這樣當程序只有daemon線程的時候,它就會自動終止運行;
c)當timer相關的所有task執行完畢以後,刪除所有此timer對象的引用(置成null),這樣timer線程也會終止;
d)調用System.exit方法,使整個程序(所有線程)終止。
⑩ Android線程池的使用
在Android中有主線程和子線程的區分。主線程又稱為UI線程,主要是處理一些和界面相關的事情,而子線程主要是用於處理一些耗時比較大的一些任務,例如一些網路操作,IO請求等。如果在主線程中處理這些耗時的任務,則有可能會出現ANR現象(App直接卡死)。
線程池,從名字的表明含義上我們知道線程池就是包含線程的一個池子,它起到新建線程、管理線程、調度線程等作用。
既然Android中已經有了線程的概念,那麼為什麼需要使用線程池呢?我們從兩個方面給出使用線程池的原因。
在Android中線程池就是ThreadPoolExecutor對象。我們先來看一下ThreadPoolExecutor的構造函數。
我們分別說一下當前的幾個參數的含義:
第一個參數corePoolSize為 核心線程數 ,也就是說線程池中至少有這么多的線程,即使存在的這些線程沒有執行任務。但是有一個例外就是,如果在線程池中設置了allowCoreThreadTimeOut為true,那麼在 超時時間(keepAliveTime) 到達後核心線程也會被銷毀。
第二個參數maximumPoolSize為 線程池中的最大線程數 。當活動線程數達到這個數後,後續添加的新任務會被阻塞。
第三個參數keepAliveTime為 線程的保活時間 ,就是說如果線程池中有多於核心線程數的線程,那麼在線程沒有任務的那一刻起開始計時,如果超過了keepAliveTime,還沒有新的任務過來,則該線程就要被銷毀。同時如果設置了allowCoreThreadTimeOut為true,該時間也就是上面第一條所說的 超時時間 。
第四個參數unit為 第三個參數的計時單位 ,有毫秒、秒等。
第五個參數workQueue為 線程池中的任務隊列 ,該隊列持有由execute方法傳遞過來的Runnable對象(Runnable對象就是一個任務)。這個任務隊列的類型是BlockQueue類型,也就是阻塞隊列,當隊列的任務數為0時,取任務的操作會被阻塞;當隊列的任務數滿了(活動線程達到了最大線程數),添加操作就會阻塞。
第六個參數threadFactory為 線程工廠 ,當線程池需要創建一個新線程時,使用線程工廠來給線程池提供一個線程。
第七個參數handler為 拒絕策略 ,當線程池使用有界隊列時(也就是第五個參數),如果隊列滿了,任務添加到線程池的時候的一個拒絕策略。
可以看到FixedThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出FixedThreadPool的幾個特點:
可以看到CacheThreadPool的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出CacheThreadPool的幾個特點:
可以看到ScheledThreadPoolExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出ScheledThreadPoolExecutor的幾個特點:
可以看到SingleThreadExecutor的構建調用了ThreadPoolExecutor的構造函數。從上面的調用中可以看出SingleThreadExecutor的幾個特點: