• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            xiaoguozi's Blog
            Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習慣原本生活的人不容易改變,就算現狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預料,人們需要更細心的觀察別人,要隨時注意才能保護別人,因為他們未必知道自己要什么·····

            轉自:http://www.cnblogs.com/-OYK/archive/2011/08/03/2126657.html

            Android的消息機制(一)

            android 有一種叫消息隊列的說法,這里我們可以這樣理解:假如一個隧道就是一個消息隊列,那么里面的每一部汽車就是一個一個消息,這里我們先忽略掉超車等種種因素,只那么先進隧道的車將會先出,這個機制跟我們android 的消息機制是一樣的。

            一、    角色描述

            1.Looper:(相當于隧道) 一個線程可以產生一個Looper 對象,由它來管理此線程里的Message Queue( 車隊,消息隧道) 。

            2.Handler: 你可以構造Handler 對象來與Looper 溝通,以便push 新消息到Message Queue 里;或者接收Looper( 從Message Queue 取出) 所送來的消息。

            3. Message Queue( 消息隊列): 用來存放線程放入的消息。

            4 .線程:UI thread 通常就是main thread ,而Android 啟動程序時會替它建立一個Message Queue 。

            每一個線程里可含有一個Looper 對象以及一個MessageQueue 數據結構。在你的應用程序里,可以定義Handler 的子類別來接收Looper 所送出的消息。

             

            在你的Android 程序里,新誕生一個線程,或執行 (Thread) 時,并不會自動建立其Message Loop 。

            Android 里并沒有Global 的Message Queue 數據結構,例如,不同APK 里的對象不能透過Massage Queue 來交換訊息(Message) 。

            例如:線程A 的Handler 對象可以傳遞消息給別的線程,讓別的線程B 或C 等能送消息來給線程A( 存于A 的Message Queue 里) 。

            線程A 的Message Queue 里的訊息,只有線程A 所屬的對象可以處理。

            使用Looper.myLooper 可以取得當前線程的Looper 對象。

            使用mHandler = new EevntHandler(Looper.myLooper()); 可用來構造當前線程的Handler 對象;其中,EevntHandler 是自已實現的Handler 的子類別。

            使用mHandler = new EevntHandler(Looper.getMainLooper()); 可誕生用來處理main 線程的Handler 對象;其中,EevntHandler 是自已實現的Handler 的子類別。

             

            這樣描述可能太抽像,下面舉幾個實際的例子來說明:

            二、    舉例

            1.  同線程內不同組件間的消息傳遞

            Looper 類用來管理特定線程內對象之間的消息交換(Message Exchange) 。你的應用程序可以產生許多個線程。而一個線程可以有許多個組件,這些組件之間常常需要互相交換訊息。如果有這種需要,您可以替線程構造一個Looper 對象,來擔任訊息交換的管理工作。Looper 對象會建立一個MessageQueue 數據結構來存放各對象傳來的消息( 包括UI 事件或System 事件等) 。如下圖:

             

            每一個線程里可含有一個Looper 對象以及一個MessageQueue 數據結構。在你的應用程序里,可以定義Handler 的子類別來接收Looper 所送出的消息。

            同線程不同組件之間的消息傳遞:

            public class Activity1 extends Activity implements OnClickListener{

                   Button button = null ;

                   TextView text = null ;

                   @Override

                   protected void onCreate(Bundle savedInstanceState) {

                          super .onCreate(savedInstanceState);

                          setContentView(R.layout. activity1 );        

                          button = (Button)findViewById(R.id. btn );

                          button .setOnClickListener( this );

                          text = (TextView)findViewById(R.id. content );

                   }

                   public void onClick(View v) {

                          switch (v.getId()) {

                          case R.id. btn :

                                 Looper looper = Looper.myLooper (); // 取得當前線程里的looper

                                 MyHandler mHandler = new MyHandler(looper); // 構造一個handler 使之可與looper 通信

                                 //buton 等組件可以由mHandler 將消息傳給looper, 再放入messageQueue, 同時mHandler 也可以接受來自looper 消息

                                 mHandler.removeMessages(0);

                                 String msgStr = " 主線程不同組件通信: 消息來自button" ;

                                 Message m = mHandler.obtainMessage(1, 1, 1, msgStr); // 構造要傳遞的消息

                                 mHandler.sendMessage(m); // 發送消息: 系統會自動調用handleMessage 方法來處理消息

                                 break ;

                            }            

                   }     

                   private class MyHandler extends Handler{             

                          public MyHandler(Looper looper){

                                 super (looper);

                          }

                          @Override

                          public void handleMessage(Message msg) { // 處理消息

                                 text .setText(msg. obj .toString());

                          }            

                   }

            }

             

            說明:

            此程序啟動時,當前線程( 即主線程, main thread) 已誕生了一個Looper 對象,并且有了一個MessageQueue 數據結構。

                looper = Looper.myLooper (); 

            調用Looper 類別的靜態myLooper() 函數,以取得目前線程里的Looper 對象.

            mHandler = new MyHandler (looper);

            構造一個MyHandler 對象來與Looper 溝通。Activity 等對象可以藉由MyHandler 對象來將消息傳給Looper ,然后放入MessageQueue 里;MyHandler 對象也扮演Listener 的角色,可接收Looper 對象所送來的消息。

            Message m = mHandler.obtainMessage(1, 1, 1, obj);

            先構造一個Message 對象,并將數據存入對象里。

            mHandler.sendMessage(m);

            就透過mHandler 對象而將消息m 傳給Looper ,然后放入MessageQueue 里。

            此時,Looper 對象看到MessageQueue 里有消息m ,就將它廣播出去,mHandler 對象接到此訊息時,會呼叫其handleMessage() 函數來處理,于是輸出"This my message!" 于畫面上,

            Android消息處理機制(二)

            角色綜述(回顧):

               (1)UI thread 通常就是main thread ,而Android 啟動程序時會替它建立一個MessageQueue 。

            (2) 當然需要一個Looper 對象,來管理該MessageQueue 。

            (3) 我們可以構造Handler 對象來push 新消息到Message Queue 里;或者接收Looper( 從Message Queue 取出) 所送來的消息。

            (4) 線程A 的Handler 對象可以傳遞給別的線程,讓別的線程B 或C 等能送訊息來給線程A( 存于A 的Message Queue 里) 。

            (5) 線程A 的Message Queue 里的消息,只有線程A 所屬的對象可以處理。

             

            子線程傳遞消息給主線程

            public class Activity2 extends Activity implements OnClickListener{

                   Button button = null ;

                   TextView text = null ;

                   MyHandler mHandler = null ;

                   Thread thread ;

                   @Override

                   protected void onCreate(Bundle savedInstanceState) {

                          super .onCreate(savedInstanceState);

                          setContentView(R.layout. activity1 );        

                          button = (Button)findViewById(R.id. btn );

                          button .setOnClickListener( this );

                          text = (TextView)findViewById(R.id. content );

                   }

                   public void onClick(View v) {

                          switch (v.getId()) {

                          case R.id. btn :

                                 thread = new MyThread();

                                 thread .start();

                                 break ;

                          }            

                   }     

                   private class MyHandler extends Handler{             

                          public MyHandler(Looper looper){

                                 super (looper);

                          }

                          @Override

                          public void handleMessage(Message msg) { // 處理消息

                                 text .setText(msg. obj .toString());

                          }            

                   }

                   private class MyThread extends Thread{

                          @Override

                          public void run() {

                                 Looper curLooper = Looper.myLooper ();

                                 Looper mainLooper = Looper.getMainLooper ();

                                 String msg ;

                                 if (curLooper== null ){

                                        mHandler = new MyHandler(mainLooper);

                                        msg = "curLooper is null" ;

                                 } else {

                                        mHandler = new MyHandler(curLooper);

                                        msg = "This is curLooper" ;

                                 }

                                 mHandler .removeMessages(0);

                                 Message m = mHandler .obtainMessage(1, 1, 1, msg);

                                 mHandler .sendMessage(m);

                          }            

                   }

            }

            說明:

            Android 會自動替主線程建立Message Queue 。在這個子線程里并沒有建立Message Queue 。所以,myLooper 值為null ,而mainLooper 則指向主線程里的Looper 。于是,執行到:

            mHandler = new MyHandler (mainLooper);

            此mHandler 屬于主線程。

               mHandler.sendMessage(m);

            就將m 消息存入到主線程的Message Queue 里。mainLooper 看到Message Queue 里有訊息,就會作出處理,于是由主線程執行到mHandler 的handleMessage() 來處理消息。

            用Android線程間通信的Message機制

            在Android 下面也有多線程 的概念,在C/C++中,子線程可以是一個函數 ,一般都是一個帶有循環的函數,來處理某些數據 ,優先線程只是一個復雜的運算過程,所以可能不需要while循環,運算完成,函數結束,線程就銷毀。對于那些需要控制的線程,一般我們都是和互斥鎖相互關聯,從而來控制線程的進度,一般我們創建子線程,一種線程是很常見的,那就是帶有消息循環的線程。
            消息循環是一個很有用的線程方式,曾經自己用C在Linux下面實現一個消息循環的機制 ,往消息隊列里添加數據,然后異步的等待消息的返回。當消息隊列為空的時候就會掛起線程,等待新的消息的加入。這是一個很通用的機制。
            在 Android,這里的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper,這個事android的新概念。我 們的主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,我們引入一個新的機制Handle,我們有消息循環,就要往消息循環里面發送相 應的消息,自定義 消息一般都會有自己對應的處理,消息的發送和清除,消息的的處理,把這些都封裝在Handle里面,注意Handle只是針對那些有Looper的線程,不管是UI線程還是子線程,只要你有Looper,我就可以往你的消息隊列里面添加東西,并做相應的處理。
            但是這里還有一點,就是只要是關于UI相關的東西,就不能放在子線程中,因為子線程是不能操作UI的,只能進行數據、系統 等其他非UI的操作。
            那么什么情況下面我們的子線程才能看做是一個有Looper的線程呢?我們如何得到它Looper的句柄呢?
            Looper.myLooper();獲得當前的Looper
            Looper.getMainLooper () 獲得UI線程的Lopper
            我們看看Handle的初始化函數,如果沒有參數,那么他就默認使用的是當前的Looper,如果有Looper參數,就是用對應的線程的Looper。
            如 果一個線程中調用Looper.prepare(),那么系統就會自動的為該線程建立一個消息隊列,然后調用 Looper.loop();之后就進入了消息循環,這個之后就可以發消息、取消息、和處理消息。這個如何發送消息和如何處理消息可以再其他的線程中通過 Handle來做,但前提是我們的Hanle知道這個子線程的Looper,但是你如果不是在子線程運行 Looper.myLooper(),一般是得不到子線程的looper的。
            public void run() {
                        synchronized (mLock) {
                            Looper.prepare();
                           //do something
                        }
                        Looper.loop();
                    }
            所以很多人都是這樣做的:我直接在子線程中新建handle,然后在子線程中發送消息,這樣的話就失去了我們多線程的意義了。
            class myThread extends Thread{
                         private EHandler mHandler ;
                         public void run() {
                             Looper myLooper, mainLooper;
                             myLooper = Looper.myLooper ();
                            mainLooper = Looper.getMainLooper ();
                            String obj;
                            if (myLooper == null ){
                                     mHandler = new EHandler(mainLooper);
                                     obj = "current thread has no looper!" ;
                            }
                            else {
                                 mHandler = new EHandler(myLooper);
                                 obj = "This is from current thread." ;
                            }
                            mHandler .removeMessages(0);
                            Message m = mHandler .obtainMessage(1, 1, 1, obj);
                            mHandler .sendMessage(m);
                         }
              }
            可以讓其他的線程來控制我們的handle,可以把 private EHandler mHandler ;放在外面,這樣我們的發消息和處理消息都可以在外面來定義,這樣增加程序 代碼 的美觀,結構更加清晰。
            對如任何的Handle,里面必須要重載一個函數
            public void handleMessage(Message msg)
            這個函數就是我們的消息處理,如何處理,這里完全取決于你,然后通過 obtainMessage和 sendMessage等來生成和發送消息, removeMessages(0)來清除消息隊列。Google 真是太智慧了,這種框架 的產生,我們寫代碼更加輕松了。
            有的時候,我們的子線程想去改變UI了,這個時候千萬不要再子線程中去修改,獲得UI線程的Looper,然后發送消息即可。
            我們看看Goole Music App的源代碼 。
            在MediaPlaybackActivity.java 中,我們可以看一下再OnCreate中的有這樣的兩句:
                    mAlbumArtWorker = new Worker("album art worker");
                    mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());
            很 明顯這兩句,是構建了一個子線程。并且這個子線程還是Looper的子線程,這里很牛逼的使用了 mAlbumArtWorker.getLooper()這個函數,因為我們知道,我們能夠得到子線程的Looper的途徑只有一個:就是在子線程中調用 Looper.myLooper (),并且這個函數還要在我們perpare之后調用才能得到正確的Looper,但是他這里用了一個這樣的什么東東 getLooper,不知道它是如何實現的?
            這里有一個大概的思路,我們在子線程的的prepare之后調用 myLooper ()這個方法,然后保存在一個成員變量中,這個getLooper就返回這個東西,但是這里會碰到多線程的一個很突出的問題,同步。我們在父線程中調用 mAlbumArtWorker.getLooper(),但是想要這個返回正確的looper就必須要求我們的子線程運行了prepare,但是這個東 西實在子線程運行的,我們如何保證呢?
            我們看Google是如何實現的?
               private class Worker implements Runnable {
                    private final Object mLock = new Object();
                    private Looper mLooper;
                    
                    /**
                     * Creates a worker thread with the given name. The thread
                     * then runs a [email=%7B@link]{@link [/email] android.os.Looper}.
                     * @param name A name for the new thread
                     */
                    Worker(String name) {
                        Thread t = new Thread(null, this, name);
                        t.setPriority(Thread.MIN_PRIORITY);
                        t.start();
                        synchronized (mLock) {
                            while (mLooper == null) {
                                try {
                                    mLock.wait();
                                } catch (InterruptedException ex) {
                                }
                            }
                        }
                    }
                    
                    public Looper getLooper() {
                        return mLooper;
                    }
                    
                    public void run() {
                        synchronized (mLock) {
                            Looper.prepare();
                            mLooper = Looper.myLooper();
                            mLock.notifyAll();
                        }
                        Looper.loop();
                    }
                    
                    public void quit() {
                        mLooper.quit();
                    }
                }
            我 們知道,一個線程類的構造函數是在主線程中完成的,所以在我們的 Worker的構造函數中我們創佳一個線程,然后讓這個線程運行,這一這個線程的創建是指定一個 Runnabl,這里就是我們的Worker本身,在主線程調用 t.start();,這后,我們子線程已經創建,并且開始執行work的run方法。然后下面的代碼很藝術:
            synchronized (mLock) {
                            while (mLooper == null) {
                                try {
                                    mLock.wait();
                                } catch (InterruptedException ex) {
                                }
                            }
                        }
            我們開始等待我們的子線程給mLooper賦值,如果不賦值我們就繼續等,然后我們的子線程在運行run方法之后,在給 mLooper賦值之后,通知worker夠著函數中的wait,然后我們的構造函數才能完成,所以我們說:
            mAlbumArtWorker = new Worker("album art worker");
            這句本身就是阻塞的,它創建了一個子線程,開啟了子線程,并且等待子線程給mLooper賦值,賦值完成之后,這個函數才返回,這樣才能保證我們的子線程的Looper的獲取 絕對是正確的,這個構思很有創意。值得借鑒

            Android中Handler的使用方法——在子線程中更新界面

            本文主要介紹Android的Handler的使用方法。Handler可以發送Messsage和Runnable對象到與其相關聯的線程的消息隊列。每個Handler對象與創建它的線程相關聯,并且每個Handler對象只能與一個線程相關聯。

            1.    Handler一般有兩種用途:1)執行計劃任務,你可以再預定的實現執行某些任務,可以模擬定時器。2)線程間通信。在Android的應用啟動時,會 創建一個主線程,主線程會創建一個消息隊列來處理各種消息。當你創建子線程時,你可以再你的子線程中拿到父線程中創建的Handler對象,就可以通過該 對象向父線程的消息隊列發送消息了。由于Android要求在UI線程中更新界面,因此,可以通過該方法在其它線程中更新界面。
            ◆ 通過Runnable在子線程中更新界面的例子

            1.○ 在onCreate中創建Handler
            public class HandlerTestApp extends Activity {
                    Handler mHandler;
                    TextView mText;
                    /** Called when the activity is first created. */
                   @Override
                   public void onCreate(Bundle savedInstanceState) {
                       super.onCreate(savedInstanceState);
                       setContentView(R.layout.main);
                       mHandler = new Handler();//創建Handler
                       mText = (TextView) findViewById(R.id.text0);//一個TextView
                   }
                 ○ 構建Runnable對象,在runnable中更新界面,此處,我們修改了TextView的文字.此處需要說明的是,Runnable對象可以再主線程中創建,也可以再子線程中創建。我們此處是在子線程中創建的。 
                 Runnable mRunnable0 = new Runnable()
                {
                            @Override
                            public void run() { 
                                    mText.setText("This is Update from ohter thread, Mouse DOWN");
                            }
                };
            ?    ○ 創建子線程,在線程的run函數中,我們向主線程的消息隊列發送了一個runnable來更新界面。

                private void updateUIByRunnable(){
                      new Thread() 
                     { 
                           //Message msg = mHandler.obtainMessage(); 
                          public void run() 
                         { 

                               //mText.setText("This is Update from ohter thread, Mouse DOWN");//這句將拋出異常
                               mHandler.post(mRunnable0); 
                         } 
                     }.start();

                 }

            ◆ 用Message在子線程中來更新界面

            1.    用Message更新界面與Runnable更新界面類似,只是需要修改幾個地方。
                ○ 實現自己的Handler,對消息進行處理

                private class MyHandler extends Handler
                { 

                    @Override
                    public void handleMessage(Message msg) { 
                        super.handleMessage(msg);
                        switch(msg.what)
                        {
                        case UPDATE ://在收到消息時,對界面進行更新
                            mText.setText("This update by message");
                            break;
                        }
                    }
                }

                ○ 在新的線程中發送消息    
                private void updateByMessage()
                {
                    //匿名對象
                     new Thread()
                     {
                            public void run()
                            {
                                //mText.setText("This is Update from ohter thread, Mouse DOWN");

                                //UPDATE是一個自己定義的整數,代表了消息ID
                                Message msg = mHandler.obtainMessage(UPDATE);
                                mHandler.sendMessage(msg);
                            }
                     }.start();
                }

            handler機制

            http://blog.csdn.net/zhenyongyuan123/archive/2010/08/23/5832727.aspx 比較詳細介紹了handler機制,大家可以參考.

            posted on 2012-03-12 23:35 小果子 閱讀(292) 評論(0)  編輯 收藏 引用 所屬分類: Android & Ios
            亚洲伊人久久成综合人影院 | 狠狠88综合久久久久综合网| 久久夜色精品国产网站| 精品久久香蕉国产线看观看亚洲| 久久婷婷五月综合色99啪ak| 久久久久人妻一区二区三区vr| 欧美久久久久久精选9999| 国产毛片欧美毛片久久久| 伊人久久大香线蕉精品| 一本久道久久综合狠狠爱| 日本三级久久网| 伊人久久大香线焦综合四虎| yy6080久久| 久久SE精品一区二区| 日韩人妻无码一区二区三区久久99| 日韩精品无码久久久久久| 青春久久| 亚洲狠狠久久综合一区77777| 久久SE精品一区二区| 久久久精品人妻无码专区不卡| 国产高清国内精品福利99久久| 亚洲欧美精品伊人久久| 亚洲va久久久噜噜噜久久狠狠 | 国内精品久久久久影院网站| 国产精品视频久久| 国产精品久久久久影视不卡| 久久频这里精品99香蕉久| 国产精品亚洲综合久久| 丁香五月综合久久激情| 精品久久久久久亚洲| 国产69精品久久久久777| 无码人妻精品一区二区三区久久久 | 日本精品久久久久中文字幕8| 久久精品成人欧美大片| 亚洲精品国产第一综合99久久| 久久综合给合综合久久| 久久久精品人妻无码专区不卡 | 亚洲欧美精品一区久久中文字幕| 国产精品女同一区二区久久| 国产精品无码久久四虎| 久久久久这里只有精品 |