Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 再論 Handler

android 再論 Handler

編輯:關於Android編程

一、ThreadLocal的分析:

從字面上這個Threadlocal很容易讓人引起誤解,認真是一個本地 thread,實際上這是一個Thread的本地信息變量,也就是說用來存儲線程中不安全變量的一個機制。分析如下:

ThreadLocal類接口很簡單,只有4個方法,我們先來了解一下:

void set(Object value)

設置當前線程的線程局部變量的值。

· public Object get()

該方法返回當前線程所對應的線程局部變量。

· public void remove()

將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束後,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量並不是必須的操作,但它可以加快內存回收的速度。

protected Object initialValue()

返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的缺省實現直接返回一個null。

對於每個線程,同名的變量,我們可以新建一個實例,並以Thread.currentThread為key保存到ThreadLocal中。當我們用到的時候,通過get()獲取。

對於Handler,通常存的是  mLooper

 

二、Handler究竟是運行在子線程還是主線程

來看看Handler的構造函數,這裡面有一個變量進行如下操作:

mLooper = Looper.myLooper();

上面的調用實際是如下操作:

public static Looper myLooper() {

        return sThreadLocal.get();

}

也就是獲取當前線程的Looper,這樣看來,Handler運行環境不是確定的,而是在哪個線程創建這個handler,在主線程創建就運行在主線程,否則就是子線程。

三、如何正確啟動一個子線程:

//在主線程先創建一個HandlerThread

HandlerThread mHandlerThread = new HandlerThread("XXX");

//第二步,是創建一個自己的Looper

mHandlerThread.start();

創建一個繼承自Handler的子類,將上面創建的Looper賦給這個子類,在創建的時候,這樣,我們就是創建一個不是運行在主線程的子線程了。否則,默認的是使用啟動Handler的線程的Looper。

    class myThread extends Handler {

    public myThread (Looper looper) {

    super(looper);

    }

   

    public myThread() {

    super();

    }

@Override

public void handleMessage(Message msg) {

// TODO Auto-generated method stub

super.handleMessage(msg);

switch (msg.what) {

case 1:

try {

Thread.sleep(20* 1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

break;

}

}

  }

//初始化

mHandlerThread = new HandlerThread("handler");

mHandlerThread.start();

//創建子線程

mHandler = new myThread(mHandlerThread.getLooper());

四、IntentService

IntentService繼承自Service,它能夠在後台運行不阻塞主線程主要歸於它內部開啟一個工作線程,也就是創建一個繼承自Handler的ServiceHandler,只是這個handler的looper是新創建的,不同於主線程的Looper,因而不會阻塞主線程。

public abstract class IntentService extends Service {

}

當我們通過Intent啟動一個IntentService的時候,先進入onCreate:

public void onCreate() {

        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");

        thread.start();

        mServiceLooper = thread.getLooper();

        mServiceHandler = new ServiceHandler(mServiceLooper);

}

是不是通過HandlerThread先創建一個Looper,然後將這個Looper賦給工作線程ServiceHandler

啟動好IntentService之後,我們開始

    public int onStartCommand(Intent intent, int flags, int startId) {

        onStart(intent, startId);

        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;

    }

    public void onStart(Intent intent, int startId) {

        Message msg = mServiceHandler.obtainMessage();

        msg.arg1 = startId;

        msg.obj = intent;

        mServiceHandler.sendMessage(msg);

}

ServiceHandler的函數中有處理消息的機制,這裡就調用onHandleIntent進行處理

    public void handleMessage(Message msg) {

        onHandleIntent((Intent)msg.obj);

        stopSelf(msg.arg1);

   }

五、如何銷毀線程

1、銷毀Handler:

由上面我們知道:我們開啟一個子線程重要的依據在於要創建一個HandlerThread,在這裡會新建一個Looper,然後通過它進行處理Message。那麼在退出時如下處理:

onDestroy() {

super.onDestroy();

//將HandlerThread的looper.quit,下面應該是實例調用quit(此處不考慮語法問題)

HandlerThread.quit();

}

對於以Handler.post(Runnable)形式發送Message的方式,在上面函數中應該是:

Handler.removeCallbacks(mRunnable);

2、銷毀Thread

目前是通過:設置一個全局變量,在退出時將這個變量設置為true,thread中判斷到這個值為true時退出thread的循環。


作者:kakaBack
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved