Android(6)——Handler,異步任務

Android

安卓開發者指南:https://developer.android.google.cn/guide

1 Handler

1.1 概念

Handler:消息分發對象,進行發送和處理消息,並且其Runable對象和一個線程的MessageQueue關聯。
爲什麼要使用Handler:解決子線程如何通知UI組件更新的問題,實現了不同線程間通信的一種機制。消息調度,將一個任務切換到某個指定的線程中去執行。多個線程併發更新UI的同時,保證線程安全。

通信機制
在這裏插入圖片描述
Handler機制的核心類:
1.Handler:作用就是發送與處理信息,如果希望Handler正常工作,在當前線程中要有一個Looper對象;
2.Looper類:爲一個線程開啓一個消息循環。通過MessageQueue來存放消息和事件,一個線程只能有一個 Looper,對應一個MessageQueue。Looper.prepare(),Looper.loop()(注意,寫在Looper.loop之後的代碼不會被執行,這個函數內部是一個循環)
3.Message:Handler接收與處理的消息對象
4.MessageQueue:消息隊列,先進先出管理Message,在初始化Looper對象時會創建一個與之關聯的MessageQueue;
UI線程:就是主線程,系統在創建UI線程的時候會初始化一個Looper對象,同時也會創建一個與其關聯的MessageQueue。

1.2 Handler使用

相關方法:
void handleMessage(Message msg):處理消息的方法,通常是用於被重寫
sendEmptyMessage(int what):發送空消息
sendEmptyMessageDelayed(int what,long delayMillis):指定延時多少毫秒後發送空信息
sendMessage(Message msg):立即發送信息
sendMessageDelayed(Message msg):指定延時多少毫秒後發送信息
final boolean hasMessage(int what):檢查消息隊列中是否包含what屬性爲指定值的消息 如果是參數爲(int what,Object object):除了判斷what屬性,還需要判斷Object屬性是否爲指定對象的消息

方式一: post(Runnable)
創建一個工作線程,實現 Runnable 接口,實現 run 方法,處理耗時操作;
創建一個 handler,通過 handler.post/postDelay,投遞創建的 Runnable,在 run 方法中進行更新 UI 操作。

new Thread(new Runnable() {
   @Override
   public void run() {
       /**
          耗時操作
        */
      handler.post(new Runnable() {
          @Override
          public void run() {
              /**
                更新UI
               */
          }
      });
   }
 }).start();

方式二: sendMessage(Message)
創建一個工作線程,繼承 Thread,重新 run 方法,處理耗時操作;
創建一個 Message 對象,設置 what 標誌及數據
通過 sendMessage 進行投遞消息
創建一個handler,重寫 handleMessage 方法,根據 msg.what 信息判斷,接收對應的信息,再在這裏更新 UI。

private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {      //判斷標誌位
            case 1:
                /**
                 獲取數據,更新UI
                */
                break;
        }
    }
};
public class WorkThread extends Thread {
    @Override
    public void run() {
        super.run();
       /**
         耗時操作
        */
        //從全局池中返回一個message實例,避免多次創建message(如new Message)
        Message msg =Message.obtain();  
        msg.obj = data;
        msg.what=1;   //標誌消息的標誌
        handler.sendMessage(msg);
    }  
}
new WorkThread().start();

1.3 Handler 存在的問題

1.UI線程/主線程/ActivityThread
2.線程不安全
3.消息循環機制:Looper

內存方面
Handler 被作爲 Activity 引用,如果爲非靜態內部類,則會引用外部類對象。當 Activity finish 時,Handler可能並未執行完,從而引起 Activity 的內存泄漏。故而在所有調用 Handler 的地方,都用靜態內部類。
異常方面
當 Activity finish 時,在 onDestroy 方法中釋放了一些資源。此時 Handler 執行到 handlerMessage 方法,但相關資源已經被釋放,從而引起空指針的異常。
避免
如果是使用 handlerMessage,則在方法中加try catch。
如果是用 post 方法,則在Runnable方法中加try catch。
Handler 的改進
內存方面:使用靜態內部類創建 handler 對象,且對 Activity 持有弱引用
異常方面:不加 try catch,而是在 onDestory 中把消息隊列 MessageQueue 中的消息給 remove 掉。

作者:空心散人
鏈接:https://www.jianshu.com/p/0a274564a4b1
來源:簡書

1.4 Handler實踐的三種效果

應用場景:
1.To schedule messages and runnables to be executed as some point in the future
2.To enqueue an action to be performed on a different thread than your own.

創建Handler,重寫方法handleMessage(Message msg)
UI線程做輕量級操作
1.Handler. sendMessage()
2.Handler.post()
3.handleMessage(Message msg)
在這裏插入圖片描述

  1. 異步下載文件更新進度條
    下載,讀寫權限,AndroidManifest.xml:
    在這裏插入圖片描述
    DownloadActivity.java:主線程–> start
    點擊按鍵
    發起下載
    開啓子線程做下載
    下載過程中通知主線程 --> 主線程更新進度條
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
  2. 倒計時的實現
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
  3. 用Handler來實現簡單打地鼠遊戲
    < ImageView>、< Button>、< TextView>
    Activity實現View.OnClickListener接口,initView(),重寫方法onClick();二維數組模擬隨機座標

2 異步任務

2.1 AsyncTask

異步,相當於多個線程,同時進行
多線程提高效率
ANR(Application Not Responding)應用程序無響應,由多線程引起的事件。

1.Main/UI Thread和Worker Thread
2. Main/UI Thread和Worker Thread之間的通信
3. Thread / Runnable線程安全
4.普通的主線程更新
Activity.runOnUiThread(Runpable)
View.post(Runnable)
View.postDelayed(Runnable, long)

異步加載實現方式:AsyncTask,多線程或者線程池
AsyncTask好處:封裝並簡化了異步操作,方便後臺線程操作後更新UI,實現了Thread和Handler的封裝,實質:Handler異步消息處理機制

常用方法:
1.泛型參數: <Params,Progress,Result>
2. UI操作 onPreExecute執行前 操作前準備工作,onPostExecute執行後在主線程中 執行結果處理
3.後臺線程操作doInBackground執行中執行耗時操作
4.輸入輸出Params, Result
5.進度顯示onProgressUpdate,收到進度然後處理,也是在UI線程中
6.取消onCancelled(Boolean aBoolean)、onCancelled()

2.2 網絡下載demo

  1. 網絡上請求數據:申請網絡權限,讀寫存儲權限
    在這裏插入圖片描述
  2. 設計界面,佈局layout
    ProgressBar,Button,TextView
    AsyncTask.java
    在這裏插入圖片描述
  3. 下載前,UI
    在這裏插入圖片描述
  4. 下載中,數據
    在另外一個線程中處理數據
    在這裏插入圖片描述
  5. 下載後,UI
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章