[Android]Handler的訊息機制

來源:互聯網
上載者:User

最經面試中,技術面試中有一個是Handler的訊息機制,細細想想,我經常用到的Handler無非是在主線程(或者說Activity)建立一個Handler對象,另外一個Thread是非同步載入資料,同時當他載入完資料後就send到主線程中的那個Handler對象,接著Handler來處理,剛才發送的一些訊息。             複製代碼 1 public class HandlerTestActivity extends Activity { 2     private TextView tv; 3     private static final int UPDATE = 0; 4     private Handler handler = new Handler() { 5  6         @Override 7         public void handleMessage(Message msg) { 8             // TODO 接收訊息並且去更新UI線程上的控制項內容 9             if (msg.what == UPDATE) {10                 // Bundle b = msg.getData();11                 // tv.setText(b.getString("num"));12                 tv.setText(String.valueOf(msg.obj));13             }14             super.handleMessage(msg);15         }16     };17 18     /** Called when the activity is first created. */19     @Override20     public void onCreate(Bundle savedInstanceState) {21         super.onCreate(savedInstanceState);22         setContentView(R.layout.main);23         tv = (TextView) findViewById(R.id.tv);24 25         new Thread() {26             @Override27             public void run() {28                 // TODO 子線程中通過handler發送訊息給handler接收,由handler去更新TextView的值29                 try {30                     for (int i = 0; i < 100; i++) {31                         Thread.sleep(500);32                         Message msg = new Message();33                         msg.what = UPDATE;34                         // Bundle b = new Bundle();35                         // b.putString("num", "更新後的值:" + i);36                         // msg.setData(b);37                         msg.obj = "更新後的值:" + i;38                         handler.sendMessage(msg);39                     }40                 } catch (InterruptedException e) {41                     e.printStackTrace();42                 }43             }44         }.start();45     }46 47 }複製代碼  ,每個Thread都一個Looper,這個Looper類是用於管理其中的訊息佇列(MessageQueue)的,那Handler是幹嘛的呢,他是用來傳遞訊息佇列的。 那下面就分析Looper、Hanlder方法吧。 Looper方法是用來處理訊息佇列的,注意了,它和線程是綁定的。 要是想在子線程中擷取一個Looper該怎麼做呢:     Looper.prepare();    Looper looper = Looper.myLooper();那麼這些都幹了哪些工作呢??? 來看下它的源碼吧: Looper: 複製代碼……//準備Looper相關事宜   public static void prepare() {     //只能有一個對象哦        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }         sThreadLocal.set(new Looper());     }   //建構函式  /*建立一個訊息佇列   * 把當前啟動並執行線程作為運行線程  */     private Looper() {        mQueue = new MessageQueue();        mRun = true;        mThread = Thread.currentThread();    }             public static final Looper myLooper() {                             //這個方法是從當前線程的ThreadLocal中拿出設定的looper                  return (Looper)sThreadLocal.get();              } /**     * Run the message queue in this thread. Be sure to call     * {@link #quit()} to end the loop.     */    public static void loop() {        Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        MessageQueue queue = me.mQueue;                // Make sure the identity of this thread is that of the local process,        // and keep track of what that identity token actually is.        Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();                while (true) {            Message msg = queue.next(); // might block            if (msg != null) {                if (msg.target == null) {                    // No target is a magic identifier for the quit message.                    return;                }                 long wallStart = 0;                long threadStart = 0;                 // This must be in a local variable, in case a UI event sets the logger                Printer logging = me.mLogging;                if (logging != null) {                    logging.println(">>>>> Dispatching to " + msg.target + " " +                            msg.callback + ": " + msg.what);                    wallStart = SystemClock.currentTimeMicro();                    threadStart = SystemClock.currentThreadTimeMicro();                }                 msg.target.dispatchMessage(msg);                 if (logging != null) {                    long wallTime = SystemClock.currentTimeMicro() - wallStart;                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;                     logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);                    if (logging instanceof Profiler) {                        ((Profiler) logging).profile(msg, wallStart, wallTime,                                threadStart, threadTime);                    }                }                 // Make sure that during the course of dispatching the                // identity of the thread wasn't corrupted.                final long newIdent = Binder.clearCallingIdentity();                if (ident != newIdent) {                    Log.wtf(TAG, "Thread identity changed from 0x"                            + Long.toHexString(ident) + " to 0x"                            + Long.toHexString(newIdent) + " while dispatching to "                            + msg.target.getClass().getName() + " "                            + msg.callback + " what=" + msg.what);                }                                msg.recycle();            }        }    }複製代碼下面就來看下Handler: 複製代碼public Handler() {        if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }      //先獲得一個Looper對象,這個要是在子線程裡,是需要先prepare()的            mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = null;    }  /**     * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than     * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).     *  If you don't want that facility, just call Message.obtain() instead.   會從訊息池裡面取得訊息佇列     */    public final Message obtainMessage()    {        return Message.obtain(this);    }複製代碼那我現在寫個小例子,是在子線程實現的訊息的傳遞。 複製代碼@Override    public void onClick(View v) {        int id = v.getId();        if (id == R.id.btn1) {            new Thread() {                 public void run() {                     Log.i("log", "run");                     Looper.prepare();                    // Looper looper = Looper.myLooper();                    Toast.makeText(MainActivity.this, "toast", 1).show();                    Handler h = new Handler() {                         @Override                        public void handleMessage(Message msg) {                            // TODO Auto-generated method stub                            super.handleMessage(msg);                            if (msg != null) {                                String strMsg = (String) msg.obj;                                System.out.println(strMsg);                            }                         }                     };                    //擷取到Handler對象的訊息                    Message msg = h.obtainMessage();                    msg.obj = "add";                    msg.sendToTarget();                     Looper.loop();// 進入loop中的迴圈,查看訊息佇列                 };             }.start();         }    }複製代碼不知你是否理解,這個小Demo中,我們需要注意: 1  子線程也是可以有Handler的,其實Handler只是從當前的線程中擷取到Looper來監聽和操作MessageQueue的。 2 子線程需要先prepare()才能擷取到Looper的,是因為在子線程只是一個普通的線程,其ThreadLoacl中沒有設定過Looper,所以會拋出異常,而在Looper的prepare()方法中sThreadLocal.set(new Looper())是設定了Looper的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.