android 實例源碼解釋,Android Handler 原理分析及實例代碼

Android Handler 原理分析

Handler一個讓無數android開發者頭疼的東西,希望我今天這邊文章能為您徹底根治這個問題

今天就為大家詳細剖析下Handler的原理

Handler使用的原因

1.多線程更新Ui會導致UI界面錯亂

2.如果加鎖會導致性能下降

3.只在主線程去更新UI,輪詢處理

Handler使用簡介

其實關鍵方法就2個一個sendMessage,用來接收消息

另一個是handleMessage,用來處理接收到的消息

下面是我參考瘋狂android講義,寫的一個子線程和主線程之間相互通信的demo

對原demo做了一定修改

public class MainActivity extends AppCompatActivity {

public final static String UPPER_NUM="upper_num";

private EditText editText;

public jisuanThread jisuan;

public Handler mainhandler;

private TextView textView;

class jisuanThread extends Thread{

public Handler mhandler;

@Override

public void run() {

Looper.prepare();

final ArrayList al=new ArrayList<>();

mhandler=new Handler(){

@Override

public void handleMessage(Message msg) {

if(msg.what==0x123){

Bundle bundle=msg.getData();

int up=bundle.getInt(UPPER_NUM);

outer:

for(int i=3;i<=up;i++){

for(int j=2;j<=Math.sqrt(i);j++){

if(i%j==0){

continue outer;

}

}

al.add(i);

}

Message message=new Message();

message.what=0x124;

Bundle bundle1=new Bundle();

bundle1.putIntegerArrayList("Result",al);

message.setData(bundle1);

mainhandler.sendMessage(message);

}

}

};

Looper.loop();

}

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

editText= (EditText) findViewById(R.id.et_num);

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

jisuan=new jisuanThread();

jisuan.start();

mainhandler=new Handler(){

@Override

public void handleMessage(Message msg) {

if(msg.what==0x124){

Bundle bundle=new Bundle();

bundle=msg.getData();

ArrayList al=bundle.getIntegerArrayList("Result");

textView.setText(al.toString());

}

}

};

findViewById(R.id.bt_jisuan).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

Message message=new Message();

message.what=0x123;

Bundle bundle=new Bundle();

bundle.putInt(UPPER_NUM, Integer.parseInt(editText.getText().toString()));

message.setData(bundle);

jisuan.mhandler.sendMessage(message);

}

});

}

}

Hanler和Looper,MessageQueue原理分析

1.Handler發送消息處理消息(一般都是將消息發送給自己),因為hanler在不同線程是可使用的

2.Looper管理MessageQueue

Looper.loop死循環,不斷從MessageQueue取消息,如果有消息就處理消息,沒有消息就阻塞

public static void loop() {

final Looper me = myLooper();

if (me == null) {

throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

}

final MessageQueue queue = me.mQueue;

// Make sure the identity of this thread is that of the local process,

// and keep track of what that identity token actually is.

Binder.clearCallingIdentity();

final long ident = Binder.clearCallingIdentity();

for (;;) {

Message msg = queue.next(); // might block

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

// This must be in a local variable, in case a UI event sets the logger

Printer logging = me.mLogging;

if (logging != null) {

logging.println(">>>>> Dispatching to " + msg.target + " " +

msg.callback + ": " + msg.what);

}

msg.target.dispatchMessage(msg);

if (logging != null) {

logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

}

// Make sure that during the course of dispatching the

// identity of the thread wasn't corrupted.

final long newIdent = Binder.clearCallingIdentity();

if (ident != newIdent) {

Log.wtf(TAG, "Thread identity changed from 0x"

+ Long.toHexString(ident) + " to 0x"

+ Long.toHexString(newIdent) + " while dispatching to "

+ msg.target.getClass().getName() + " "

+ msg.callback + " what=" + msg.what);

}

msg.recycleUnchecked();

}

}

這個是Looper.loop的源碼,實質就是一個死循環,不斷讀取自己的MessQueue的消息

3.MessQueue一個消息隊列,Handler發送的消息會添加到與自己內聯的Looper的MessQueue中,受Looper管理

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

這個是Looper構造器,其中做了2個工作,

1.生成與自己關聯的Message

2.綁定到當前線程

主線程在初始化的時候已經生成Looper,

其他線程如果想使用handler需要通過Looper.prepare()生成一個自己線程綁定的looper

這就是Looper.prepare()源碼,其實質也是使用構造器生成一個looper

private static void prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(new Looper(quitAllowed));

}

4.handler發送消息會將消息保存在自己相關聯的Looper的MessageQueue中,那它是如何找到這個MessageQueue的呢

public Handler(Callback callback, boolean async) {

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 = callback;

mAsynchronous = async;

}

這個是Handler的構造方法,它會找到一個自己關聯的一個Looper

public static Looper myLooper() {

return sThreadLocal.get();

}

沒錯,他們之間也是通過線程關聯的,得到Looper之后自然就可以獲得它的MessageQueue了

5.我們再看下handler如發送消息,又是如何在發送完消息后,回調HandlerMessage的

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

msg.target = this;

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg, uptimeMillis);

}

這個就是Handler發送消息的最終源碼,可見就是將一個message添加到MessageQueue中,那為什么發送完消息又能及時回調handleMessage方法呢

大家請看上邊那個loop方法,其中的for循環里面有一句話msg.target.dispatchMessage(msg);

public void dispatchMessage(Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

這就是這句話,看到了吧里面會調用hanlerMessage,一切都聯系起來了吧

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/533751.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/533751.shtml
英文地址,請注明出處:http://en.pswp.cn/news/533751.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

amd cpu排行_最新intel和amd處理器性能排行cpu天梯圖2019

現在市面上cpu廠家有很多&#xff0c;比如常見的intel系列的、amd系列CPU&#xff0c;cpu對電腦起著至關重要的作用&#xff0c;所以我們需要知道cpu性能的好壞&#xff0c;為此小編這就給大家帶來最新intel和amd處理器性能排行對比天梯圖&#xff0c;大家可以了解一下吧。inte…

python中的對象列表_Python內建的對象列表

Python內建的對象列表剛寫Python肯定會遇到這樣的情況&#xff0c;想寫些什么&#xff0c;但又不知從何寫起...在我看來問題在于我們不知道有什么東東可以拿來玩&#xff0c;這里列出Python的內建對象&#xff0c;稍微歸類了一下&#xff0c;多看幾遍代碼自然筆上生花&#xff…

電腦會顯示android,怎么在電腦上顯示、操作安卓手機

想要在電腦上顯示、操作安卓手機&#xff0c;該怎么辦&#xff0c;那么怎么在電腦上顯示、操作安卓手機的呢?下面是學習啦小編收集整理的怎么在電腦上顯示、操作安卓手機&#xff0c;希望對大家有幫助~~在電腦上顯示、操作安卓手機的方法工具/原料windows操作系統安卓手機電腦…

git version是什么軟件_Deepin 15.11 安裝 ZoneMinder 視頻監控軟件

Zoneminder是一款開源的視頻監控軟件&#xff0c;可以很方便的連接ip攝像頭。因計劃將家中的監控攝像頭引入NAS&#xff0c;在一臺deepin系統的筆記本是先進行了測試。UBUNTU和debian系統都是很容易安裝這個軟件的。未來在NAS上用docker啟動一個專門的zoneminder&#xff0c;do…

看不出svp補幀_專業補幀軟件SVP4 實現PotPlayer視頻補幀教程

雖然能實現幀率翻倍&#xff0c;不過現在視頻絕大多數都是24幀或25幀&#xff0c;翻倍也才48幀&#xff0c;沒辦法實現補幀后達到60幀的效果。SVP4是一款專業版視頻補幀軟件&#xff0c;提供GPU加速&#xff0c;并允許使用中檔CPU和幾乎任何GPU硬件為60Hz的FullHD 1080p視頻重新…

android 通知歷史,Android P新特性:追蹤應用通知歷史

原標題&#xff1a;Android P新特性&#xff1a;追蹤應用通知歷史IT之家3月9日消息 不久前&#xff0c;谷歌已經正式推出了首個Android P開發者預覽版&#xff0c;包含了許多新特性。對此&#xff0c;IT之家也進行了一系列報道。該系統的新特性也正在不斷被發現。例如最新消息顯…

文件另存為時名稱會改變_易經:人處在困境時,不要焦慮,改變固定習慣,就會迎來轉機...

我讀《易經》&#xff0c;悟到一些規律&#xff1a;人的一生&#xff0c;起起落落&#xff0c;時而順利&#xff0c;時而受困&#xff0c;都是正常現象&#xff0c;沒有必要把困難和壓力看得太重。人處在困境時&#xff0c;不要焦慮&#xff0c;只要改變你的固定習慣&#xff0…

ubuntu系統寫路由指令_在Ubuntu中如何查看網絡路由表詳解,

在Ubuntu中如何查看網絡路由表詳解&#xff0c;什么是Linux中的路由和路由表&#xff1f;路由的過程意味著IP包在網絡上從一點傳輸到另一點。當你向某人發送電子郵件時&#xff0c;你實際上是在將一系列IP數據包或數據報從你的系統傳輸到另一個人的計算機上。從計算機發送的數據…

jspdf html轉換pdf,使用jspdf將HTML轉換為pdf時出錯

對于一個角度項目,我試圖將包含HTML代碼的字符串變量轉換為pdf文件。我安置了所有的家屬,比如:jspdf格式光柵化HTML我的代碼如下:b64DecodeUnicode(str) {return decodeURIComponent(atob(str).split().map(function(c) {return % (00 c.charCodeAt(0).toString(16)).slice(-…

澄海哪里學機器人編程_終于發現小孩有必要學機器人編程嗎

讓孩子學習編程的目的&#xff0c;就像其他教育方式一樣&#xff0c;只是希望能幫助孩子找到他的興趣點&#xff0c;打開孩子的獲取知識和能力的大門。一起來看看一篇小孩有必要學機器人編程嗎。小孩有必要學機器人編程嗎編程和英語類似&#xff0c;屬于基本技能&#xff0c;未…

鴻蒙系統替代iOS,華為橫空出世!鴻蒙系統,能否替代安卓IOS?

原標題&#xff1a;華為橫空出世&#xff01;鴻蒙系統&#xff0c;能否替代安卓IOS&#xff1f;從長遠來看&#xff0c;華為主推鴻蒙系統是必然的選擇。畢竟安卓系統為谷歌的&#xff0c;而由于美國限制&#xff0c;讓華為格外被動。命運掌握在自己手里&#xff0c;才有足夠的話…

ubuntu安裝python3.8_將 Ubuntu 16 和 18 上的 python 升級到最新 python3.8 的方法教程

1. 概述 本文記錄在 Ubuntu 16.04 上將 python 升級為 3.8 版本&#xff0c;并配置為系統默認 python3 的過程。 在 Ubuntu 16.04 中&#xff0c;python3 的默認版本為 3.5&#xff1a; $ python3 -V Python 3.5.2 本文以在 Ubuntu 16.04 中安裝為例&#xff0c;方法同樣適用于…

java怎么表示正無窮大_java中怎樣表示一個無窮大? 無窮小?

Java中提供了三個特殊的浮點數值&#xff1a;正無窮大、負無窮大、非數&#xff0c;用于表示溢出和出錯。正無窮大&#xff1a;用一個正數除以0將得到一個正無窮大&#xff0c;通過Double或Float的POSITIVE_INFINITY表示。負無窮大&#xff1a;用一個負數除以0將得到一個負無窮…

ng bind html 無效,angularjs中ng-bind-html的用法總結

本篇主要講解angular中的$sanitize這個服務.此服務依賴于ngSanitize模塊.(這個模塊需要加載angular-sanitize.js插件)要學習這個服務,先要了解另一個指令: ng-bing-html.顧名思義,ng-bind-html和ng-bind的區別就是,ng-bind把值作為字符串,和元素的內容進行綁定,但是ng-bind-htm…

熱門搜索怎么實現_三個步驟教你學會,搜索引擎霸屏技術!

做好SEO就要了解搜索引擎霸屏技術&#xff0c;它是在百度中搜索關鍵字來檢索信息。整個畫面的推薦都是你的內容。那么客戶點擊你的可能性就會增加&#xff01;那么搜索引擎霸屏技術這么好&#xff0c;那要如何做到呢&#xff1f;1.要想成為霸屏&#xff0c;第一步要選擇好的關鍵…

ethtool用法 linux_Linux命令之Ethtool用法詳解

Linux/Unix命令之Ethtool描述&#xff1a;Ethtool是用于查詢及設置網卡參數的命令。概要&#xff1a;ethtool ethX //查詢ethX網口基本設置ethtool –h //顯示ethtool的命令幫助(help)ethtool –i ethX //查詢ethX網口的相關信息ethtool –d ethX //查詢ethX…

html字體如何設置垂直居中顯示,css文字水平垂直居中怎么設置?

css文字水平垂直居中怎么設置&#xff1f;下面本篇文章就來給大家介紹使用CSS設置文字水平居中和垂直居中的方法。有一定的參考價值&#xff0c;有需要的朋友可以參考一下&#xff0c;希望對大家有所幫助。1、文字水平居中在CSS中想要讓文字水平居中&#xff0c;可以使用text-a…

python for循環例子_Python for循環生成列表的實例

Python for循環生成列表的實例 一般Python for語句前不加語句&#xff0c;但我在機器學習實戰中看到了這兩條語句&#xff1a; featList [example[i] for example in dataSet] classList [example[-1] for example in dataSet] 多方研究和詢問&#xff0c;得到如下解釋&#…

HTML5鏈接tcpUDP,UDP/TCP協議 網絡調試工具源碼(C#)

本代碼包括了TCP和UDP的客戶端和服務端&#xff0c;適合C#初學者學習、參考資源下載此資源下載價格為2D幣&#xff0c;請先登錄資源文件列表NetWork/NetWork.sln , 990NetWork/NetWork.v12.suo , 27648NetWork/NetWork/App.config , 187NetWork/NetWork/bin/Debug/NetWork.exe …

沒有shell63號單元_ansys-SHELL單元

Q:用板殼元shell63單元建模時,如下圖示,兩個平面互相垂直,如何使這兩個平面保持為一個整體來受力.因為實際結構中,比如一個由鋼板焊成的箱梁,內有加勁隔板,如何模擬.由于這兩個面沒有公共邊,用了粘貼及搭接都不行,試問怎樣簡單實現整體性這一目的.A:分網時控制單元長度&#xf…