當前位置:ag真人国际官网-ag旗舰厅官方网站 » 安卓系統 » handleandroid

handleandroid-ag真人国际官网

發布時間: 2024-07-07 08:02:21

㈠ android 線程可以有幾個handle

android.os.handler handler在android里負責發送和處理消息。它的主要用途有: 1)按計劃發送消息或執行某個runnanble(使用post方法); 2)從其他線程中發送來的消息放入消息隊列中,避免線程沖突(常見於更新ui線程) 默認情況下,handler接受的是當前線程下的消息循環實例(使用handler(looper looper)、handler(looper looper, handler.callback callback)可以指定線程),同時一個消息隊列可以被當前線程中的多個對象進行分發、處理(在ui線程中,系統已經有一個activity來處理了,你可以再起若干個handler來處理)。在實例化handler的時候,looper可以是任意線程的,只要有handler的指針,任何線程也都可以sendmessage。handler對於message的處理不是並發的。一個looper 只有處理完一條message才會讀取下一條,所以消息的處理是阻塞形式的(handlemessage()方法里不應該有耗時操作,可以將耗時操作放在其他線程執行,操作完後發送message(通過sendmessges方法),然後由handlemessage()更新ui)。 android中handle類的用法 當我們在處理下載或是其他需要長時間執行的任務時,如果直接把處理函數放activity的oncreate或是onstart中,會導致執行過程中整個activity無響應,如果時間過長,程序還會掛掉。handler就是把這些功能放到一個單獨的線程里執行,與activity互不影響。 當用戶點擊一個按鈕時如果執行的是一個常耗時操作的話,處理不好會導致系統假死,用戶體驗很差,而android則更進一步,如果任意一個acitivity沒有響應5秒鍾以上就會被強制關閉,因此我們需要另外起動一個線程來處理長耗時操作,而主線程則不受其影響,在耗時操作完結發送消息給主線程,主線程再做相應處理。那麼線程之間的消息傳遞和非同步處理用的就是handler。 加群討論研究 qq群:56839077

㈡ android中handle和線程的關系是什麼

作者:李板溪
鏈接:http://www.hu.com/question/24766848/answer/53037579
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。

問題背景,假設你要下載一張美女圖顯示出來。 使用這個問題就可以說明主要的問題了。
好了 上代碼,下載美女圖片,然後顯示在 imageview 中。 代碼如下:
public class mainactivity extends appcompatactivity {

public static final string beautyurl = "http://ww3.sinaimg.cn/large/.jpg";
imageview mbeautyimageview;
@override
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.activity_main);
mbeautyimageview = (imageview)findviewbyid(r.id.beauty);
mbeautyimageview.setimagebitmap(downloadimage(beautyurl));
}

@nullable
public bitmap downloadimage(string urlstring){
try {
final url url = new ;
try(inputstream is = url.openstream()){
return bitmapfactory.decodestream(is);
}
} catch (ioexception e) {
e.printstacktrace();
return null;
}
}

}

然後這樣的一段看似沒有問題的代碼,在 android 3 以上是會直接報錯的。 主要錯誤原因在
caused by: android.os.networkonmainthreadexception at android.os.strictmode$androidblockguardpolicy.onnetwork(strictmode.java:1147)
為了保證用戶體驗, android 在 3.0 之後,就不允許在 主線程(mainthread)即 ui線程 中執行網路請求了。 那怎麼辦呢?
好吧,我們暫不考試 android 提供的一系統組件及工具類, 用純 java 的方式來解決這個問題。
在新的線程中下載顯示圖片
在新創建的線程中下載顯示圖片如下:
new thread(new runnable() {
@override
public void run() {
mbeautyimageview.setimagebitmap(downloadimage(beautyurl));
}
}).start();

看起來來錯的樣子,跑起來看看。 啊,又報錯了。
android.view.viewrootimpl$: only the original thread that created a view hierarchy can touch its views.
說只能在創建view 層級結構的線程中修改它。 創建它的線程就是主線程。 在別的線程不能修改。 那怎麼辦?
那現在我們遇到的問題是: 下載不能在主線程下載。 更新imageview 一定要在 主線程中進行。 在這樣的限制下,我們自然而然想去一個解決辦法: 就是在新創建的線程中下載。 下載完成在主線程中更新 imageview。
但是,怎麼在下載完成之後,將圖片傳遞給主線程呢?這就是我們問題的關鍵了。
線程間通信
我們的通信要求,當下載線程中下載完成時,通知主線程下載已經完成,請在主線程中設置圖片。 純 java 的實現上面的線程間通信的辦法我暫沒有找到,於是我想到使用 futuretask 來實現在主線程中等待圖片下載完成,然後再設置。
futuretask bitmapfuturetask = new futuretask<>(new callable() {
@override
public bitmap call() throws exception {
return downloadimage(beautyurl);
}
});
new thread(bitmapfuturetask).start();
try {
bitmap bitmap = bitmapfuturetask.get();
mbeautyimageview.setimagebitmap(bitmap);
} catch (interruptedexception |executionexception e) {
e.printstacktrace();
}

不過這雖然騙過了 android 系統,但是雖然系統阻塞的現象沒有解決。 例如我在 get() 方法前後設置了輸出語句:
log.i(tag,"waiting bitmap");
bitmap bitmap = bitmapfuturetask.get();
log.i(tag,"finished download bitmap");

設置了下載時間至少 5 秒鍾之後,輸出如下:
06-27 23:30:18.058 21298-21298/com.banxi1988.androiditc i/mainactivity﹕ waiting bitmap 06-27 23:30:23.393 21298-21298/com.banxi1988.androiditc i/mainactivity﹕ finished download bitmap
讓主線程什麼事做不做,就在那傻等了半天。然後由於 oncreate沒有返回。用戶也就還沒有看到界面。 導致說應用半天啟動不了。。卡死了。。
查閱了一些資料,沒有不用 android 的框架層的東西而實現在其他進程執行指定代碼的。
而 android 中線程間通信就得用到 android.os.handler 類了。 每一個 handler 都與一個線程相關聯。 而 handler 的主要功能之一便是: 在另一個線程上安插一個需要執行的任務。
這樣我的問題就通過一個 handler 來解決了。
於是 oncreate 中的相關代碼變成如下了:
final handler mainthreadhandler = new handler();

new thread(new runnable() {
@override
public void run() {
final bitmap bitmap = downloadimage(beautyurl);
mainthreadhandler.post(new runnable() {
@override
public void run() {
mbeautyimageview.setimagebitmap(bitmap);
}
});
}
}).start();

看起來很酷的樣子嘛,一層套一層的 runnable. mainthreadhandler 因為是在 主線程中創建的, 而 handler創建時,綁定到當前線程。 所以 mainthreadhandler 綁定到主線程中了。
當然 android 為了方便你在向主線程中安排進操作,在 activity類中提供了 runonuithread 方法。 於是上面的代碼簡化為:
new thread(new runnable() {
@override
public void run() {
final bitmap bitmap = downloadimage(beautyurl);
runonuithread(new runnable() {
@override
public void run() {
mbeautyimageview.setimagebitmap(bitmap);
}
});
}
}).start();

你不用自己創建一個 handler了。
而 runonuithread 的具體實現,也跟我們做得差不多。ui線程即主線程。
public final void runonuithread(runnable action) {
if (thread.currentthread() != muithread) {
mhandler.post(action);
} else {
action.run();
}
}

handler 與 loop 簡介
上面說到 每一個 handler 都與一個線程相綁定。 實際上是,通過 handler 與 loop 綁定,而每一個 loop 都與一個線程想綁定的。 比如 handler 中兩個主要構造函數大概如下:
public handler(...){
mlooper = looper.mylooper();
// ...
}

public handler(looper looper,...){
mlooper = looper;
// ...
}

public static looper mylooper() {
return sthreadlocal.get();
}

然後 looper 的構造函數如下:
private looper(boolean quitallowed) {
mqueue = new messagequeue(quitallowed);
mthread = thread.currentthread();
}

綁定了當前的線程和生成了一個消息隊列。
值得提起的一點是, looper 類保持了對 應用的主線程的 looper 對象的靜態應用。
private static looper smainlooper; // guarded by looper.class
public static looper getmainlooper() {
synchronized (looper.class) {
return smainlooper;
}
}

這樣就可以方便你在其他線程中,使用一個綁定到主線程的 handler,從而方便向主線程安插任務。 例如一般的圖片處理庫即是如此。這樣你只要指定一個 圖片的 url,及要更新的imageview 即可。 如 picasso 庫可以用如下代碼的讀取並更新圖片。 picasso.with(context).load(url).into(imageview);
然後 handler 可以做的事情還有很多。 因為它後面有 looper 有 messagequeue。可以深入了解下。
談一下線程池與 asynctask 類
android 早期便有這個便利的類來讓我們方便的處理 工作線程及主線程的交互及通信。 但是現在先思考一下,我們上面的代碼可能遇到的問題。 比如,我們現在要顯示一個圖片列表。 一百多張圖片。 如果每下載一張就開一個線程的話,那一百多個線程,那系統資源估計支持不住。特別是低端的手機。
正確的做法是使用一個線程池。
final executorservice executor = executors.newcachedthreadpool();
executor.execute(new runnable() {
@override
public void run() {
final bitmap bitmap = downloadimage(beautyurl);
runonuithread(new runnable() {
@override
public void run() {
mbeautyimageview.setimagebitmap(bitmap);
}
});
executor.shutdown();
}
});

由於我們是在在一個局部方法中使用了一個線程池。所以處理完了之後應該將線程停止掉。 而我們上面只有一個線程,所以直接在下載完成之後,調用 executor停掉線程池。 那如果執行了多個圖片的下載請求。需要怎麼做呢? 那就要等他們都完成時,再停止掉線程池。 不過這樣用一次就停一次還是挺浪費資源的。不過我們可以自己保持一個應用級的線程池。 不過這就麻煩不少。
然後 android 早已經幫我們想法了這一點了。 我們直接使用 asynctask 類即可。
於是我們下載圖片並顯示圖片的代碼如下:
new asynctask(){
@override
protected bitmap doinbackground(string... params) {
return downloadimage(params[0]);
}

@override
protected void onpostexecute(bitmap bitmap) {
mbeautyimageview.setimagebitmap(bitmap);
}
}.execute(beautyurl);

相比之前的代碼簡潔不少。
看一下 asynctask 的源代碼,正是集合我們之前考慮的這些東西。
一個全局的線程池
public static final executor thread_pool_executor
= new threadpoolexecutor(core_pool_size, maximum_pool_size, keep_alive,
timeunit.seconds, spoolworkqueue, sthreadfactory);

一個綁定主線程的 handler ,在線程中處理傳遞的消息
private static class internalhandler extends handler {
public internalhandler() {
super(looper.getmainlooper());
}

@suppresswarnings({"unchecked", "rawuseofparameterizedtype"})
@override
public void handlemessage(message msg) {
asynctaskresult result = (asynctaskresult) msg.obj;
switch (msg.what) {
case message_post_result:
// there is only one result
result.mtask.finish(result.mdata[0]);
break;
case message_post_progress:
result.mtask.onprogressupdate(result.mdata);
break;
}
}
}

小結
android 提供的 looper 和 handler 可以讓我們非常方便的在各線程中安排可執行的任務

㈢ android中handle在內部類中為什麼不執行

當android應用啟動的時候,會先創建一個應用主線程的looper對象,looper實現了一個簡單的消息隊列,一個一個的處理裡面的message對象。主線程looper對象在整個應用生命周期中存在。
當在主線程中初始化handler時,該handler和looper的消息隊列關聯。發送到消息隊列的message會引用發送該消息的handler對象,這樣系統可以調用 handler#handlemessage(message) 來分發處理該消息。
在java中,非靜態(匿名)內部類會引用外部類對象。而靜態內部類不會引用外部類對象。
如果外部類是activity,則會引起activity泄露 。
當activity finish後,延時消息會繼續存在主線程消息隊列中1分鍾,然後處理消息。而該消息引用了activity的handler對象,然後這個handler又引用了這個activity。這些引用對象會保持到該消息被處理完,這樣就導致該activity對象無法被回收,從而導致了上面說的 activity泄露。
要修改該問題,只需要按照lint提示的那樣,把handler類定義為靜態即可,然後通過weakreference 來保持外部的activity對象。

㈣ android在主線程中使用handle.postdelay做延時操作對主線程資源消耗大嗎

android在主線程中使用handle.postdelay做延時操作對主線程資源消耗不大,因為handler中有一個消息池,是靜態的消息池, 建議去了解一下android中的handler, looper, messagequeue之間的關系就知道了.

熱點內容
sqlserver如何切換主備伺服器 發布:2024-07-17 16:23:02 瀏覽:297
mc18伺服器ip 發布:2024-07-17 16:23:02 瀏覽:377
仙境傳說手游腳本 發布:2024-07-17 16:09:24 瀏覽:690
matlab命令窗口和新建腳本 發布:2024-07-17 15:51:26 瀏覽:374
建ftp文件夾 發布:2024-07-17 15:51:26 瀏覽:954
魔獸撿物腳本 發布:2024-07-17 15:27:56 瀏覽:129
開發ip伺服器 發布:2024-07-17 15:24:42 瀏覽:387
安卓系統視頻製作哪個好用 發布:2024-07-17 15:10:47 瀏覽:210
androidapk結構 發布:2024-07-17 15:10:43 瀏覽:945
c語言指針的例子 發布:2024-07-17 15:08:01 瀏覽:768
网站地图