當前位置:首頁 » 安卓系統 » 安卓looper怎麼工作的

安卓looper怎麼工作的

發布時間: 2023-01-24 07:59:03

Ⅰ android中looper的實現原理,為什麼調用looper.prepare就在當前線程關聯了一個lo

實際上:消息發送和計劃任務提交之後,它們都會進入某線程的消息隊列中,我們可以把這個線程稱之為目標線程。不論是主線程還是子線程都可以成為目標線程。上例中之所以在主線程中處理消息,是因為我們要更新UI,按照android中的規定我們必須由主線程更新UI。所以我們讓主線程成為了目標線程。

那麼如何控制讓某個線程成為目標線程呢?

這就引出了Looper的概念。Android系統中實現了消息循環機制,Android的消息循環是針對線程的,每個線程都可以有自己的消息隊列和消息循環。Android系統中的通過Looper幫助線程維護著一個消息隊列和消息循環。通過Looper.myLooper()得到當前線程的Looper對象,通過Looper.getMainLooper()得到當前進程的主線程的Looper對象。
前面提到每個線程都可以有自己的消息隊列和消息循環,然而我們自己創建的線程默認是沒有消息隊列和消息循環的(及Looper),要想讓一個線程具有消息處理機制我們應該在線程中先調用Looper.prepare()來創建一個Looper對象,然後調用Looper.loop()進入消息循環。如上面的源碼所示。
當我們用Handler的構造方法創建Handler對象時,指定handler對象與哪個具有消息處理機制的線程(具有Looper的線程)相關聯,這個線程就成了目標線程,可以接受消息和計劃任務了。Handler中的構造方法如下:

[java] view
plainprint?

public Handler() {

if (FIND_POTENTIAL_LEAKS) {

final Class<? extends Handler> klass = getClass();

if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&

(klass.getModifiers() & Modifier.STATIC) == 0) {

Log.w(TAG, "The following Handler class should be static or leaks might occur: " +

klass.getCanonicalName());

}

}

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = null;

}

public Handler(Looper looper) {

mLooper = looper;

mQueue = looper.mQueue;

mCallback = null;

}
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}

public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}

在上述的計時器的例子中,之所以可以在主線程中處理消息而我們自己並沒有調用Looper.prepare()等方法,是因為Android系統在Activity啟動時為其創建一個消息隊列和消息循環,當我們用無參的Handler構造方法創建對象時又用了當前線程的Looper對象,及將handler與主線程中的Looper對象進行了關聯。

android中是使用Looper機制來完成消息循環的,但每次創建線程時都先初始化Looper比較麻煩,因此Android為我們提供了一個HandlerThread類,他封裝了Looper對象,是我們不用關心Looper的開啟和釋放問題。

不管是主線程還是其他線程只要有Looper的線程,別的線程就可以向這個線程的消息隊列中發送消息和任務。

我們使用HandlerThread類代替上一篇文章中的子線程,並用HandlerThread類中的Looper對象構造Handler,則接受消息的目標線程就不是主線程了,而是HandlerThread線程。代碼如下:

[java] view
plainprint?

public class clockActivity extends Activity {

/** Called when the activity is first created. */

private String TAG="clockActivity";

private Button endButton;

private TextView textView;

private int timer=0;

private boolean isRunning=true;

private Handler handler;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

endButton=(Button)findViewById(R.id.endBtn);

textView=(TextView)findViewById(R.id.textview);

endButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

isRunning=false;

}

});

HandlerThread thread=new HandlerThread("myThread");

handler=new Handler(thread.getLooper());//與HandlerThread中的Looper對象關聯

thread.start();

Runnable r=new Runnable(){

@Override

public void run() {

// TODO Auto-generated method stub

if(isRunning){

textView.setText("走了"+timer+"秒");

timer++;

handler.postDelayed(this, 1000);//提交任務r,延時1秒執行

}

}

};

handler.postDelayed(r, 1000);

}

}
public class clockActivity extends Activity {
/** Called when the activity is first created. */
private String TAG="clockActivity";
private Button endButton;
private TextView textView;
private int timer=0;
private boolean isRunning=true;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
endButton=(Button)findViewById(R.id.endBtn);
textView=(TextView)findViewById(R.id.textview);
endButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
isRunning=false;
}
});
HandlerThread thread=new HandlerThread("myThread");
handler=new Handler(thread.getLooper());//與HandlerThread中的Looper對象關聯
thread.start();
Runnable r=new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
if(isRunning){
textView.setText("走了"+timer+"秒");
timer++;
handler.postDelayed(this, 1000);//提交任務r,延時1秒執行
}
}
};
handler.postDelayed(r, 1000);
}
}

此時處理任務會在handlerThread線程中完成。當然這個例子會出線異常:依然是因為在非主線程中更新了UI。這樣做只是為了大家能夠理解這種機制。

深入理解Android消息處理機制對於應用程序開發非常重要,也可以讓我們對線程同步有更加深刻的認識,希望這篇文章可以對朋友們有所幫助。

Ⅱ android looper 怎麼理解

Android

Looper

handler
的聯系及處理

最近一直在看
Android
內核的代碼。把
Looper

Handler
這一節先分享一下:

Handle
主要起一個代理中介的作用,具體對象要向底層發請求,得通過
Handler

Handler
把這個請求放進對應的
MessageQueue
(消息隊列)中,而
MessageQueue
是由
Looper
來維護的。
Looper
中有一個循環,循環讀取
MessageQueue
中的請求,發給相應的底層處理(這個過程有點復雜)。當底層
有信息返回時,
也會先放進
MessageQueue
中,
然後對應的
Looper
遍歷,
交給對
應的
Handler
處理。
Handler
找出對應的回調函數或其他已注冊的相關方法,讓
其進行處理,最終在界面有一個反應。

以下是我寫的一個
demo

主要是如何關聯
Looper

Handler

以及對應的線程

MessageQueue

Looper
的一個成員)。

1.
測試方法入口:
testLooper1.java
package com.linquan.test.loop1;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class testLooper1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(MyConstant.TAG, "main start...");
new MyThread().start();
Message msg = new Message();
msg.what = MyConstant.CONSTANT3;
while(MyThread.h == null){
Log.d(MyConstant.TAG, "handler is not init ! please wait a
monment....");
try {
Thread.sleep(300);//
由於這里是測試,
所以加上此行代碼,
避免出錯。

際中多為用戶觸發事件,此時
handle
應該已經初始化了。

} catch (InterruptedException e) {
e.printStackTrace();

Ⅲ android裡面所說的looper是什麼意思啊

Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。
Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message
msg)方法來對特定的Message進行處理,例如更新UI等。
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。
Thread:線程,負責調度整個消息循環,即消息循環的執行場所

Ⅳ looper的作用 android 為什麼要循環

給你舉個例子:

用handler傳遞消息時候。你先sendmessage。這時候消息到looper然後你再looper當中更具msg.what獲取相應的消息。looper相當於一個消息收取中介。所以要有循環。我自己的理解。

Ⅳ Android的handler機制的原理

Android的handler機制的原理分為非同步通信准備,消息發送,消息循環,消息處理。

1、非同步通信准備

在主線程中創建處理器對象(Looper)、消息隊列對象(Message Queue)和Handler對象。

2、消息入隊

工作線程通過Handler發送消息(Message) 到消息隊列(Message Queue)中。

3、消息循環

消息出隊: Looper循環取出消息隊列(Message Queue) 中的的消息(Message)。

消息分發: Looper將取出的消息 (Message) 發送給創建該消息的處理者(Handler)。

4、消息處理

處理者(Handler) 接收處理器(Looper) 發送過來的消息(Message),根據消息(Message) 進行U操作。

handler的作用

handler是android線程之間的消息機制,主要的作用是將一個任務切換到指定的線程中去執行,(准確的說是切換到構成handler的looper所在的線程中去出處理)android系統中的一個例子就是主線程中的所有操作都是通過主線程中的handler去處理的。

Handler的運行需要底層的 messagequeue和 looper做支撐。



Ⅵ [Android源碼分析] - 非同步通信Handler機制

一、問題:在Android啟動後會在新進程里創建一個主線程,也叫UI線程( 非線程安全 )這個線程主要負責監聽屏幕點擊事件與界面繪制。當Application需要進行耗時操作如網路請求等,如直接在主線程進行容易發生ANR錯誤。所以會創建子線程來執行耗時任務,當子線程執行完畢需要通知UI線程並修改界面時,不可以直接在子線程修改UI,怎麼辦?

解決方法:Message Queue機制可以實現子線程與UI線程的通信。

該機制包括Handler、Message Queue、Looper。Handler可以把消息/ Runnable對象 發給Looper,由它把消息放入所屬線程的消息隊列中,然後Looper又會自動把消息隊列里的消息/Runnable對象 廣播 到所屬線程里的Handler,由Handler處理接收到的消息或Runnable對象。

1、Handler

每次創建Handler對象時,它會自動綁定到創建它的線程上。如果是主線程則默認包含一個Message Queue,否則需要自己創建一個消息隊列來存儲

Handler是多個線程通信的信使。比如在線程A中創建AHandler,給它綁定一個ALooper,同時創建屬於A的消息隊列AMessageQueue。然後在線程B中使用AHandler發送消息給ALooper,ALooper會把消息存入到AMessageQueue,然後再把AMessageQueue廣播給A線程里的AHandler,它接收到消息會進行處理。從而實現通信。

2、Message Queue

在主線程里默認包含了一個消息隊列不需要手動創建。在子線程里,使用Looper.prepare()方法後,會先檢查子線程是否已有一個looper對象,如果有則無法創建,因為每個線程只能擁有一個消息隊列。沒有的話就為子線程創建一個消息隊列。

Handler類包含Looper指針和MessageQueue指針,而Looper里包含實際MessageQueue與當前線程指針。

下面分別就UI線程和worker線程講解handler創建過程:

首先,創建handler時,會自動檢查當前線程是否包含looper對象,如果包含,則將handler內的消息隊列指向looper內部的消息隊列,否則,拋出異常請求執行looper.prepare()方法。

 - 在 UI線程 中,系統自動創建了Looper 對象,所以,直接new一個handler即可使用該機制;

- 在 worker線程 中,如果直接創建handler會拋出運行時異常-即通過查『線程-value』映射表發現當前線程無looper對象。所以需要先調用Looper.prepare()方法。在prepare方法里,利用ThreadLocal<Looper>對象為當前線程創建一個Looper(利用了一個Values類,即一個Map映射表,專為thread存儲value,此處為當前thread存儲一個looper對象)。然後繼續創建handler, 讓handler內部的消息隊列指向該looper的消息隊列(這個很重要,讓handler指向looper里的消息隊列,即二者共享同一個消息隊列,然後handler向這個消息隊列發送消息,looper從這個消息隊列獲取消息) 。然後looper循環消息隊列即可。當獲取到message消息,會找出message對象里的target,即原始發送handler,從而回調handler的handleMessage() 方法進行處理。

 - handler與looper共享消息隊列 ,所以handler發送消息只要入列,looper直接取消息即可。

 - 線程與looper映射表 :一個線程最多可以映射一個looper對象。通過查表可知當前線程是否包含looper,如果已經包含則不再創建新looper。

5、基於這樣的機制是怎樣實現線程隔離的,即在線程中通信呢。 

核心在於 每一個線程擁有自己的handler、message queue、looper體系 。而 每個線程的Handler是公開 的。B線程可以調用A線程的handler發送消息到A的共享消息隊列去,然後A的looper會自動從共享消息隊列取出消息進行處理。反之一樣。

二、上面是基於子線程中利用主線程提供的Handler發送消息出去,然後主線程的Looper從消息隊列中獲取並處理。那麼還有另外兩種情況:

1、主線程發送消息到子線程中;

採用的方法和前面類似。要在子線程中實例化AHandler並設定處理消息的方法,同時由於子線程沒有消息隊列和Looper的輪詢,所以要加上Looper.prepare(),Looper.loop()分別創建消息隊列和開啟輪詢。然後在主線程中使用該AHandler去發送消息即可。

2、子線程A與子線程B之間的通信。

1、 Handler為什麼能夠實現不同線程的通信?核心點在哪?

不同線程之間,每個線程擁有自己的Handler、消息隊列和Looper。Handler是公共的,線程可以通過使用目標線程的Handler對象來發送消息,這個消息會自動發送到所屬線程的消息隊列中去,線程自帶的Looper對象會不斷循環從裡面取出消息並把消息發送給Handler,回調自身Handler的handlerMessage方法,從而實現了消息的線程間傳遞。

2、 Handler的核心是一種事件激活式(類似傳遞一個中斷)的還是主要是用於傳遞大量數據的?重點在Message的內容,偏向於數據傳輸還是事件傳輸。

目前的理解,它所依賴的是消息隊列,發送的自然是消息,即類似事件中斷。

0、 Android消息處理機制(Handler、Looper、MessageQueue與Message)

1、 Handler、Looper源碼閱讀

2、 Android非同步消息處理機制完全解析,帶你從源碼的角度徹底理解

謝謝!

wingjay

![](https://avatars0.githubusercontent.com/u/9619875?v=3&s=460)

Ⅶ android裡面所說的looper是什麼意思啊

Looper即:有消息循環的線程。
在Android里線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper,這個事android的新概念。主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,引入一個新的機制Handle,有消息循環,就要往消息循環里 面發送相應的消息,自定義消息一般都會有對應的處理,消息的發送和清除,消息的處理,把這些都封裝在Handle裡面,注意Handle只是針對那些有Looper的線程,不管是UI線程還是子線程,只要有Looper,就可以往消息隊列裡面添加東西,並做相應的處理。

Ⅷ Handler的工作原理。為什麼在子線程中使用Handler會拋出異常

Handler了它在安卓中常見的工作就是子線程與主線程的通信,其實可以直接歸類為線程和線程間的通信

談到Handler會涉及到以下幾個類
Handler、Message、Looper、MessageQueue
我們一個一個來說,首先設置場景在一個線程中通知另一個線程

1,創建Looper和創建MessageQueue
首先在一個線程里要用Handler,那麼需要准備Looper,調用Looper.prepare(),我們在主線程裡面不用准備Looper,那麼是因為在我們的主線程中已經給我們初始化好了Looper,
在准備Looper的時候會去校驗這個線程中是否存在Looper,如果有Looper那麼拋出異常(注意:有一些面試官會問如何判斷一個線程中是否存在一個Looper的,它用的是ThreadLocal,它的作用是在線程范圍內保證變數的唯一性,Thread中會維護一個類似HashMap的東西,然後用ThreadLocal對象作為key,value就是要存儲的變數值,這樣就保證了存儲數據的唯一性)
如果沒有Looper那麼new一個Looper,new Looper的同時會new 一個MessageQueue(注意:一個線程中只有一個Looper一個MessageQueue)
然後Looper.loop()就可以啟動輪訓來輪訓消息隊列了
2,創建Handler
這個我們在熟悉不過了,繼承一個Handler然後復寫handlerMessage方法,這里其實面試官也可以問一些比較細致的問題,如下

注意:有面試官會問可以創建幾個Handler,我負責任的說是多個,哪個Handler發送的消息哪個Handler處理(吐槽一下有的面試官,你自己把自己要問的問題搞清楚了在去問別人,非要跟我犟只能創建一個)

3,創建Message
Message一般都是使用Message.obtain(),它這裡面是有一個spool指向一個Message對象,還有一個next指向下一個Message,它裡面維護了一個鏈表,obtain的時候在表頭頭取Message,在Message回收的時候在表頭添加一個Message,類似棧,默認大小是50
4,消息的處理
Handler對象sendMessage發送消息放入的MessageQueue隊列中,Looper輪訓到它,然後就開始處理Message,Message會有一個target去記錄是哪個Handler發送的它,會調用這個Handler中的dispatchMessage()方法,如果說Message中實現了CallBack那麼調用Message中的CallBack,如果Handler中實現了Callback調用Handler中CallBack,否則就都調動Handler中的handleMessage方法

根據上面的原理分析,那就是因為你子線程中沒有Looper,給他一個Looper就好了

Ⅸ Android-Looper

Looper.loop是一個死循環,拿不到需要處理的Message就會阻塞,那在UI線程中為什麼不會導致ANR?

首先我們來看造成ANR的原因:
1.當前的事件沒有機會得到處理(即主線程正在處理前一個事件,沒有及時的完成或者looper被某種原因阻塞住了)
2.當前的事件正在處理,但沒有及時完成

我們再來看一下APP的入口ActivityThread的main方法:

顯而易見的,如果main方法中沒有looper進行死循環,那麼主線程一運行完畢就會退出,會導致直接崩潰,還玩什麼!

現在我們知道了消息循環的必要性,那為什麼這個死循環不會造成ANR異常呢?

我們知道Android 的是由事件驅動的,looper.loop() 不斷地接收事件、處理事件,每一個點擊觸摸或者說Activity的生命周期都是運行在 Looper的控制之下,如果它停止了,應用也就停止了。只能是某一個消息或者說對消息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它,這也就是我們為什麼不能在UI線程中處理耗時操作的原因。
主線程Looper從消息隊列讀取消息,當讀完所有消息時,主線程阻塞。子線程往消息隊列發送消息,喚醒主線程,主線程被喚醒只是為了讀取消息,當消息讀取完畢,再次睡眠。因此loop的循環並不會對CPU性能有過多的消耗。

初始化當前線程和Looper,這樣可以在實際開始啟動循環(loop())之前創建一個Handler並且關聯一個looper。確保在先調用這個方法,然後調用loop()方法,並且通過調用quit()結束。

這裡面的入參boolean表示Looper是否允許退出,true就表示允許退出,對於false則表示Looper不允許退出。

初始化當前當前線程的looper。並且標記為一個程序的主Looper。由Android環境來創建應用程序的主Looper。因此這個方法不能由咱們來調用。另請參閱prepare()

這里的sThreadLocal.get()是和prepare(boolean)方法裡面的sThreadLocal.set(new Looper(quitAllowed));一一對應的。而在prepareMainLooper()方法裡面。

退出循環
將終止(loop()方法)而不處理消息隊列中的任何更多消息。在調用quit()後,任何嘗試去發送消息都是失敗的。例如Handler.sendMessage(Message)方法將返回false。因為循環終止之後一些message可能會被無法傳遞,所以這個方法是不安全的。可以考慮使用quitSafely()方法來確保所有的工作有序地完成。

安全退出循環
調用quitSafely()方法會使循環結束,只要消息隊列中已經被傳遞的所有消息都將被處理。然而,在循環結束之前,將來不會提交處理延遲消息。
調用退出後,所有嘗試去發送消息都將失敗。就像調用Handler.sendMessage(Message)將返回false。

熱點內容
碧藍航線pc掛機腳本 發布:2024-05-19 02:30:03 瀏覽:588
腳本fir 發布:2024-05-19 02:28:57 瀏覽:260
阿里雲獨享伺服器 發布:2024-05-19 02:23:54 瀏覽:253
織夢源碼ga 發布:2024-05-19 02:23:20 瀏覽:571
java文件名後綴 發布:2024-05-19 02:14:39 瀏覽:956
快手點榜腳本 發布:2024-05-19 02:08:44 瀏覽:163
pythonforinkeys 發布:2024-05-19 01:55:44 瀏覽:793
電腦如何區域網共享文件夾 發布:2024-05-19 01:25:01 瀏覽:69
手機存儲越大性能越好嗎 發布:2024-05-19 01:14:28 瀏覽:177
我的世界hyp伺服器怎麼玩 發布:2024-05-19 00:51:25 瀏覽:801