android的handle
『壹』 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 在別的地方怎麼獲取到handle對象
這個問題應該算是java的基礎吧,在別的地方這是個可見性的問題。同一個類中:
classTest{
Handleh;
publicTest(){
h=newHandler();
}
}
全局變數,在Test中都是可用的。
不同的類中,Android中自帶一個Application全局變數:
{
publicHandlerh;
}
//然後在你創建的地方將這個handler賦值給application中的
((MyApplication)getApplication()).h=this.h;
//於是你可以再其他地方拿到這個handler了
((MyApplication)getApplication()).h.sendxxxx
當然了,你可能在《app研發錄》中看到過不要把奇奇怪怪的東西放到Application中這個說法,我也同意,不過你可以將handler傳過去,咋傳根據你的需求來,大概的思路就跟Application里差不多,拿到一個對象調用public方法設置Handler。
『叄』 android怎麼區分handler
重寫handler 的一個方法 handleMessage(android.os.Message msg)
通過handler.sendMessage(msg)發送一個消息過來他就會接收到
通過msg的what值區分消息
例如:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if(msg.what == 1) {
Toast.makeText(MainActivity.this, "收到消息一", 1).show();
}else if (msg.what == 2) {
Toast.makeText(MainActivity.this, "收到消息二", 1).show();
}
}
};
『肆』 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中Handler的主要作用是什麼通俗點,初學。
Handler的使用主要是android中無法在主線程(即UI線程)中訪問網路、無法在子線程中訪問UI線程元素。
一般是在子線程中訪問網路,然後使用Handler發送message通知主線程處理UI更新操作
『陸』 如何生動形象的理解Android Handler消息處理機制
在一個Android 程序開始運行的時候,會單獨啟動一個Process。默認的情況下,所有這個程序中的Activity,Service,Content Provider,Broadcast Receiver(Android 4大組件)都會跑在這個Process。一個Android 程序默認情況下也只有一個Process,但一個Process下卻可以有許多個Thread。在這么多Thread當中,有一個Thread,稱之為UI Thread。UI Thread在Android程序運行的時候就被創建,是一個Process當中的主線程Main Thread,主要是負責控制UI界面的顯示、更新和控制項交互。在Android程序創建之初,一個Process呈現的是單線程模型,所有的任務都在一個線程中運行。因此,UI Thread所執行的每一個函數,所花費的時間都應該是越短越好。而其他比較費時的工作(訪問網路,下載數據,查詢資料庫等),都應該交由子線程去執行,以免阻塞主線程,導致ANR。那麼問題來了,UI 主線程和子線程是怎麼通信的呢。這就要提到這里要講的Handler機制。
簡單來說,handler機制被引入的目的就是為了實現線程間通信的。handler一共幹了兩件事:在子線程中發出message,在主線程中獲取、處理message。聽起來好像so easy,如果面試中讓闡述下Handler機制,這么回答顯然不是面試官想要的答案。忽略了一個最重要的問題:子線程何時發送message,主線程何時獲取處理message。
為了能讓主線程「適時」得處理子線程所發送的message,顯然只能通過回調的方式來實現——開發者只要重寫Handler類中處理消息的方法,當子線程發送消時,Handler類中處理消息的方法就會被自動回調。
Handler類包含如下方法用於發送處理消息
void handleMessage(Message msg):處理消息的方法,該方法通常用於被重寫。
final boolean hasMessage(int what):檢查消息隊列中是否包含what屬性為指定值的消息。
final boolean hasMessage(int what,Object object):檢查消息隊列中是否包含what屬性為指定值且object屬性為指定對象的消息。
sendEmptyMessage(int what)發送空消息。
sendEmptyMessageDelayed(int what,longdelayMillis);指定多少毫秒之後發送空消息。
sendMessage(Message msg)立即發送消息。
sendMessageDelayed(int what,longdelayMillis);指定多少毫秒之後發送消息。
藉助以上方法,就可以自由穿梭於主線程和子線程之中了。
到這里就結束了么?當然沒有。要講的東西才剛剛開始,要知道消息處理這件事,不是handler一個人在戰斗,android的消息處理有三個核心類:Handler,Looper,和Message。其實還有一個MessageQueue(消息隊列),但是Message Queue被封裝到Looper裡面了,不會直接與Message Queue打交道。
Looper的字面意思是「循環裝置」,它被設計用來使一個普通線程變成Looper線程。所謂Looper線程就是循環工作的線程。在程序開發中,經常會需要一個線程不斷循環,一旦有新任務則執行,執行完繼續等待下一個任務,這就是Looper線程。Looper是用於給一個線程添加一個消息隊列(MessageQueue),並且循環等待,當有消息時會喚起線程來處理消息的一個工具,直到線程結束為止。通常情況下不會用到Looper,因為對於Activity,Service等系統組件,Frameworks已經為初始化好了線程(俗稱的UI線程或主線程),在其內含有一個Looper,和由Looper創建的消息隊列,所以主線程會一直運行,處理用戶事件,直到某些事件(BACK)退出。
如果,需要新建一個線程,並且這個線程要能夠循環處理其他線程發來的消息事件,或者需要長期與其他線程進行復雜的交互,這時就需要用到Looper來給線程建立消息隊列。
使用Looper也非常的簡單,它的方法比較少,最主要的有四個:
public static prepare();為線程初始化消息隊列。
public static myLooper();獲取此Looper對象的引用
public static loop();讓線程的消息隊列開始運行,可以接收消息了。
public void quit();退出具體哪個Looper
在整個消息處理機制中,message又叫task,封裝了任務攜帶的信息和處理該任務的handler,這個很好理解,就不做介紹了。
說了這么多,一定沒聽太明白。沒關系,再對Handler運行機製做個總結:
子線程(無looper)借用主線程(有looper)里的Hander發送一條message到主線程,這個message會被主線程放入message queue,主線程裡面有一個looper,在輪詢message queue的時候發現有一條message。調用handler消息處理者,執行handlemessage方法,去處理這個message,就可以在handlemessage的方法裡面更新ui。好像畫面感不是太強,舉個例子吧。試想有一個生產方便麵的車間,這個車間有兩條生產線,一條是生產面餅的,一條是生產調料包的,面餅的生產線比較先進一點,配備了一個工人叫handler,還配備了一個調料包分類循環器。這個車間能生產很多種方便麵,有老壇酸菜,有泡椒鳳爪,有香菇燉雞,有紅燒牛肉等等。其中方便麵的面餅都是一樣的,只有調料包和包裝袋不一樣,包裝袋是根據調料包來定的。那麼生產線運作起來了:工人Handler把子生產線(子線程)上的調料包(message)放到了主生產線(主線程)上的調料包分類循環器(Looper)上,通過輪詢分類篩選後工人Handler確定這是一包合格的老壇酸菜味調料包,於是工人把老壇酸菜調料包和面餅放在一塊(sendmessage),告訴主生產線,這是一包老壇酸菜方便麵,請給這包方便麵包一個老壇酸菜的包裝袋(更新UI).
『柒』 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中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 URL(urlString);
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<Bitmap> bitmapFutureTask = new FutureTask<>(new Callable<Bitmap>() {
@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<String,Void,Bitmap>(){
@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 可以讓我們非常方便的在各線程中安排可執行的任務