国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android Handler機制

2019-11-09 17:51:01
字體:
來源:轉載
供稿:網友

  在Android中提供了一種異步回調機制Handler,使用它,我們可以在完成一個很長時間的任務后做出相應的通知

    handler基本使用:

        在主線程中,使用handler很簡單,new一個Handler對象實現其handleMessage方法,在handleMessage中提供收到消息后相應的處理方法即可,這里不對handler使用進行詳細說明,在看本博文前,讀者應該先掌握handler的基本使用,我這里主要深入描述handler的內部機制

   .現在我們首先就有一個問題,我們使用myThreadHandler.sendEmptyMessage(0);發送一個message對象,那么Handler是如何接收該message對象并處理的呢?我先畫一個數據結構圖:

   

從這個圖中我們很清楚可以看到調用sendEmptyMessage后,會把Message對象放入一個MessageQueue隊列,該隊列屬于某個Looper對象,每個Looper對象通過ThreadLocal.set(new Looper())跟一個Thread綁定了,Looper對象所屬的線程在Looper.Loop方法中循環執行從MessageQueue隊列讀取Message對象,并把Message對象交由Handler處理,調用Handler的dispatchMessage方法。

     現在我們再來看一下使用Handler的基本實現代碼:

               // 主線程中新建一個handler                normalHandler = new Handler() {                        public void handleMessage(android.os.Message msg) {                                btnSendMsg2NormalHandler.setText("normalHandler");                                Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--normalHandler handleMessage run...", Thread.currentThread()                                                .getName()));                        }                };

...//發送消息到hanldermyThreadHandler.sendEmptyMessage(0); 

你現在已經很清楚了sendEmptyMessage到handleMessage的過程,途中經過Looper.MessageQueue隊列,轉由Looper所在的線程去處理了,這是一個異步的過程,當然Looper所在的線程也可以是sendEmptyMessage所在的線程。 

     看了上面你也許還是迷惑不解,那么什么要Looper了,跟我們要用的Handler又有啥鳥關系呢?

     我在前面一直強調在主線程中使用handler,為什么要這么說呢,因為你在自己new一個新線程中去像我前面那樣簡單建立一個Handler,程序執行是會報錯的:

    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.PRepare()     at android.os.Handler.<init>(Handler.java:121)     at com.cao.android.demos.handles.HandleTestActivity$MyThread$1.<init>(HandleTestActivity.java:86)     at com.cao.android.demos.handles.HandleTestActivity$MyThread.run(HandleTestActivity.java:86)

    為什么在主線程中不會報錯,而在自己新見的線程中就會報這個錯誤呢?很簡單,因為主線程它已經建立了Looper,你可以打開ActivityThread的源碼看一下:

    public static final void main(String[] args) {        SamplingProfilerIntegration.start();

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();        thread.attach(false);

       Looper.loop();

        if (Process.supportsProcesses()) {            throw new RuntimeException("Main thread loop unexpectedly exited");        }

        thread.detach();        String name = (thread.mInitialapplication != null)            ? thread.mInitialApplication.getPackageName()            : "<unknown>";        Slog.i(TAG, "Main thread of " + name + " is now exiting");    }

    在main函數中它已經做了這個事情了,為什么要調用 Looper.prepareMainLooper(); Looper.loop();我們可以進去看一下,在prepareMainLooper方法中新建了一個looper對象,并與當前進程進行了綁定,而在Looper.loop方法中,線程建立消息循環機制,循環從MessageQueue獲取Message對象,調用  msg.target.dispatchMessage(msg);進行處理msg.target在myThreadHandler.sendEmptyMessage(0)設置進去的,因為一個Thead中可以建立多個Hander,通過msg.target保證MessageQueue中的每個msg交由發送message的handler進行處理,那么Handler又是怎樣與Looper建立聯系的呢,在Handler構造函數中有這樣一段代碼:

       mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;

在新建Handler時需要設置mLooper成員,Looper.myLooper是從當前線程中獲取綁定的Looper對象:

public static final Looper myLooper() {        return (Looper)sThreadLocal.get();    }

    若Looper對象沒有創建,就會拋異常"Can't create handler inside thread that has not called Looper.prepare()"這跟我前面講的是一致的。所以我們在一個新線程中要創建一個Handler就需要這樣寫:

        class MyThread extends Thread {

                public void run() {                                       Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]-- run...", Thread                                        .currentThread().getName()));                        // 其它線程中新建一個handler                        Looper.prepare();// 創建該線程的Looper對象,用于接收消息,在非主線程中是沒有looper的所以在創建handler前一定要使用prepare()創建一個Looper                        myThreadHandler = new Handler() {                                public void handleMessage(android.os.Message msg) {                                        Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler handleMessage run...", Thread                                                        .currentThread().getName()));                                }                        };                        Looper.myLooper().loop();//建立一個消息循環,該線程不會退出                }        }

   現在,你應該對Handler的機制有所了解了吧,若有什么疑問,歡迎在評論中提出

  在其它線程中Handler使用主線程的Looper

   前面我說了在新線程中要新建一個Handler需要調用Looper.prepare();也有另一種方法就是使用主線程中的Looper,那就不必新建Looper對象了:

                        threadMainLoopHandler =new Handler(Looper.getMainLooper()){                                public void handleMessage(android.os.Message msg) {                                        Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--threadMainLoopHandler handleMessage run...", Thread                                                        .currentThread().getName()));                                                                       }                                //該handleMessage方法將在mainthread中執行                        };

  這時候注意不要在handleMessage做太多的操作,因為它在主線程中執行,會影響主線程執行ui更新操作。

    使用Message.callback回調

   public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }從dispatchMessage定義可以看出,如果Message對象自帶callback對象,handler不會執行handleMessage方法而是執行message.callback中定義的run方法,當然callback還是在handler關聯的looper所綁定的線程中執行的。實際上Handler.post(Runnable r)方法就是把r添加到一個msg.callback的,也就是說,下面兩種寫法,沒有什么區別:

1.使用Message.callback

[java] view plain copyMessage msg = Message.obtain(myThreadHandler,new Runnable() {            @Override      public void run() {          Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",                  Thread.currentThread().getName()));       }  });  myThreadHandler.sendMessage(msg);  

2.使用Handler.post

[java] view plain copymyThreadHandler.post(new Runnable() {                                            @Override                      public void run() {                          Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",                                  Thread.currentThread().getName()));                       }                  });  

注:對于Handler機制相關測試,我寫了一個測試類:

http://download.csdn.NET/source/3275970

3.Handler對Activity finish影響。

在開發的過程中碰到一個棘手的問題,調用Activity.finish函數Acitivity沒有執行生命周期的ondestory函數,后面查找半天是因為有一個handler成員,因為它有一個delay消息沒有處理,調用Activity.finish,Activity不會馬上destory,所以記得在Ativity finish前清理一下handle中的未處理的消息,這樣Activity才會順利的destory


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 崇明县| 隆子县| 东平县| 云浮市| 兴国县| 中宁县| 焦作市| 洛川县| 凤翔县| 宁陕县| 稻城县| 瑞丽市| 汾西县| 同德县| 台东市| 镇巴县| 东明县| 确山县| 兴海县| 高密市| 阜康市| 红桥区| 临邑县| 鄯善县| 康乐县| 同江市| 大丰市| 孝感市| 沈丘县| 巴楚县| 绥阳县| 开化县| 双城市| 大竹县| 醴陵市| 深水埗区| 赤城县| 繁昌县| 长垣县| 蓬安县| 和静县|