在android中,有很多功能是不能放在onCreate或者onStart方法里面,因為這些功能相對

          來說費時比較長,比如說下載一個文件,下載的過程比較長,但是如果寫在Activity中,

          那么這段時間Activity是完全沒有響應(yīng)的,那么就可以將這種處理大量數(shù)據(jù)或者耗時比較

          長的東西放在一個單獨的線程中來完成,即Activity是一個線程,而下載的是在另外一個

          線程,那么這樣就可以使得下載跟Activity之間互不影響,從而得到了良好的用戶體驗

           

          這里有兩種隊列,一種是線程隊列,就是用postXX方法或者removeCallbacks方法對線程對象的操作。另一種是消息隊列,用sendMessage和handleMessage方法來對消息對象進行處理

           



           

          handler采用的是一個消息隊列的方式,每一個handler都有一個與之關(guān)聯(lián)的消息隊列,而且是先進先出的方式執(zhí)行,即:每次加入一個handler,然后拿出來,對其進行處理,然后再拿出另一個,再進行處理

           

          例子一:這個例子僅僅是對線程對象進行操作的測試

          Java代碼  收藏代碼
          1. package org.hualang.handler;  
          2.   
          3. import android.app.Activity;  
          4. import android.os.Bundle;  
          5. import android.os.Handler;  
          6. import android.view.View;  
          7. import android.widget.Button;  
          8.   
          9. public class HandlerTest extends Activity {  
          10.       
          11.     private Button mybutton1;  
          12.     private Button mybutton2;  
          13.     @Override  
          14.     public void onCreate(Bundle savedInstanceState) {  
          15.         super.onCreate(savedInstanceState);  
          16.         setContentView(R.layout.main);  
          17.           
          18.         mybutton1 = (Button)findViewById(R.id.mybutton1);  
          19.         mybutton2 = (Button)findViewById(R.id.mybutton2);  
          20.           
          21.         mybutton1.setOnClickListener(new Button.OnClickListener()  
          22.         {  
          23.   
          24.             @Override  
          25.             public void onClick(View arg0) {  
          26.                 /** 
          27.                  * 調(diào)用Handler的post方法,將要執(zhí)行的線程對象添加到 
          28.                  * 線程隊列中 
          29.                  */  
          30.                 handler.post(updateThread);  
          31.             }  
          32.               
          33.         });  
          34.         mybutton2.setOnClickListener(new Button.OnClickListener()  
          35.         {  
          36.   
          37.             @Override  
          38.             public void onClick(View v) {  
          39.                 // TODO Auto-generated method stub  
          40.                 handler.removeCallbacks(updateThread);  
          41.             }  
          42.               
          43.         });    
          44.           
          45.     }  
          46.     //創(chuàng)建Handler對象  
          47.     Handler handler = new Handler();  
          48.     /** 
          49.      * 將要執(zhí)行的操作卸載寫入線程對象的run()方法當(dāng)中 
          50.      */  
          51.     Runnable updateThread = new Runnable()  
          52.     {  
          53.         public void run()  
          54.         {  
          55.             System.out.println("更新線程");  
          56.             //在run方法內(nèi)部,執(zhí)行postXX的方法,每隔3秒會執(zhí)行一次  
          57.             handler.postDelayed(updateThread, 3000);  
          58.         }  
          59.     };  
          60. }  

           

          運行結(jié)果如下:



           程序解釋:首先創(chuàng)建一個Handler對象,然后創(chuàng)建一個繼承自Runnable接口的線程

          程序首先點擊按鈕“開始”,于是會馬上執(zhí)行post方法,將執(zhí)行的線程對象添加到線程隊列中,這時會馬上執(zhí)行

          Java代碼  收藏代碼
          1. public void run()  
          2.         {  
          3.             System.out.println("更新線程");  
          4.             //在run方法內(nèi)部,執(zhí)行postXX的方法,每隔3秒會執(zhí)行一次  
          5.             handler.postDelayed(updateThread, 3000);  
          6.         }  

           

          然后,執(zhí)行postDelayed方法,由于里面設(shè)置的間隔時間,所以每3秒會調(diào)價一個handler對象到線程隊列中,并且一直執(zhí)行,直到點擊“結(jié)束”按鈕,調(diào)用removeCallbacks方法將其從線程隊列中移除

           

           

          例子2:下面的例子將簡單的對線程對象和消息對象進行處理

          Java代碼  收藏代碼
          1. package org.hualang.handlertest2;  
          2.   
          3. import android.app.Activity;  
          4. import android.os.Bundle;  
          5. import android.os.Handler;  
          6. import android.os.Message;  
          7. import android.view.View;  
          8. import android.widget.Button;  
          9. import android.widget.ProgressBar;  
          10.   
          11. public class HandlerTest2 extends Activity {  
          12.     private ProgressBar bar = null;  
          13.     private Button start = null;  
          14.     @Override  
          15.     public void onCreate(Bundle savedInstanceState) {  
          16.         super.onCreate(savedInstanceState);  
          17.         setContentView(R.layout.main);  
          18.         bar = (ProgressBar)findViewById(R.id.progress1);  
          19.         start = (Button)findViewById(R.id.start);  
          20.         start.setOnClickListener(new Button.OnClickListener()  
          21.         {  
          22.   
          23.             @Override  
          24.             public void onClick(View v) {  
          25.                 bar.setVisibility(View.VISIBLE);  
          26.                 handler.post(handlerThread);  
          27.             }  
          28.               
          29.         });  
          30.     }  
          31.     /** 
          32.      * 使用匿名內(nèi)部類來復(fù)寫hanlder當(dāng)中的hanldrMessage方法 
          33.      * 這里的msg對象就是從線程部分發(fā)送過來的對象 
          34.      */  
          35.     Handler handler = new Handler()  
          36.     {  
          37.         public void handleMessage(Message msg)  
          38.         {  
          39.             bar.setProgress(msg.arg1);  
          40.             handler.post(handlerThread);  
          41.         }  
          42.     };  
          43.     //線程類,該類使用的是匿名內(nèi)部類的方式進行聲明  
          44.     Runnable handlerThread = new Runnable()  
          45.     {  
          46.         int i = 0;  
          47.         public void run()  
          48.         {  
          49.             System.out.println("開始線程");  
          50.             i = i + 10;  
          51.             /** 
          52.              * 得到一個消息對象,Message類是由android操作系統(tǒng)提供 
          53.              * obtainMessage方法用來得到Message對象 
          54.              */  
          55.             Message msg = handler.obtainMessage();  
          56.             /** 
          57.              * Message中有個成員變量,即msg獨享的arg1參數(shù) 
          58.              * 將其值設(shè)置為i。用arg1或arg2這兩個成員變量傳遞 
          59.              * 消息,優(yōu)點是系統(tǒng)性能消耗較少 
          60.              */  
          61.             msg.arg1 = i;  
          62.             try {  
          63.                 //當(dāng)前線程休眠1秒  
          64.                 Thread.sleep(5000);  
          65.             } catch (InterruptedException e) {  
          66.                 // TODO Auto-generated catch block  
          67.                 e.printStackTrace();  
          68.             }  
          69.             /** 
          70.              * 發(fā)送一個消息,用sendMessage是將msg加入到消息 
          71.              * 隊列中。而post是將線程加入到線程隊列中 
          72.              */  
          73.             handler.sendMessage(msg);  
          74.             if( i == 100)  
          75.             {  
          76.                 /** 
          77.                  * 如果i=100的時候,就將線程對象 
          78.                  * 從handler當(dāng)中移除 
          79.                  */  
          80.                 handler.removeCallbacks(handlerThread);  
          81.                 bar.setVisibility(View.GONE);  
          82.             }  
          83.         }  
          84.     };  
          85. }  

            

          main.xml

          Xml代碼  收藏代碼
          1. <?xml version="1.0" encoding="utf-8"?>  
          2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
          3.     android:orientation="vertical"  
          4.     android:layout_width="fill_parent"  
          5.     android:layout_height="fill_parent"  
          6.     >  
          7. <ProgressBar  
          8.     android:id="@+id/progress1"  
          9.     android:layout_width="fill_parent"  
          10.     android:layout_height="wrap_content"  
          11.     android:visibility="gone"  
          12.     style="?android:attr/progressBarStyleHorizontal"  
          13. />  
          14. <Button  
          15.     android:id="@+id/start"  
          16.     android:layout_width="wrap_content"  
          17.     android:layout_height="wrap_content"  
          18.     android:gravity="center"  
          19.     android:text="點擊我"  
          20. />  
          21. </LinearLayout>  

           

          運行結(jié)果:



           

           

          程序說明:

          1、當(dāng)點擊按鈕后,會執(zhí)行按鈕的onClick方法中的

          Java代碼  收藏代碼
          1. bar.setVisibility(View.VISIBLE);  
          2. handler.post(handlerThread);  

           將進度條顯示出來,并且將線程對象加入到線程隊列中

          2、線程對象對先打印出一個“開始線程”,然后i的值增加10,然后從系統(tǒng)中獲取一個Message對象

          3、將i賦給Message對象的參數(shù)arg1

          4、當(dāng)前線程休眠5秒,然后通過sendMessage方法發(fā)送一個Message對象發(fā)送到消息隊列中

          5、然后再執(zhí)行,通過handleMessage方法設(shè)置進度條的值,并且將其加入到進程隊列中

          Java代碼  收藏代碼
          1. Handler handler = new Handler()  
          2.     {  
          3.         public void handleMessage(Message msg)  
          4.         {  
          5.             bar.setProgress(msg.arg1);  
          6.             handler.post(handlerThread);  
          7.         }  
          8.     };  

           6、循環(huán)執(zhí)行,直到i=100,進度條隱藏,并將線程對象從線程隊列中取出






          對于Handler來說,它和與它調(diào)用它的Activity是出于同一線程的,上一篇并沒有調(diào)用線程
          的start方法,而是直接執(zhí)行的run方法。而啟動一個線程是調(diào)用的start方法

          上一篇博客里的對Handler的調(diào)用時通過Runnable接口來實現(xiàn)的,并且是通過run()方法來啟動那個線程的,而且是Activity和 Handler是兩個線程獨立運行的,互補干擾,但是實際情況確實,Activity所在的線程和Handler的線程是同一個線程,下面進行一下實驗

           

          Java代碼  收藏代碼
          1. package org.hualang.handlertest3;  
          2.   
          3. import android.app.Activity;  
          4. import android.os.Bundle;  
          5. import android.os.Handler;  
          6. import android.util.Log;  
          7.   
          8. public class HandlerTest3 extends Activity {  
          9.     private Handler handler = new Handler();  
          10.     private String TAG = "System.out";  
          11.     @Override  
          12.     public void onCreate(Bundle savedInstanceState) {  
          13.         super.onCreate(savedInstanceState);  
          14.         handler.post(r);  
          15.         setContentView(R.layout.main);  
          16.         //Thread t = new Thread(r);  
          17.         //t.start();  
          18.           
          19.         Log.d(TAG,"Activity id:"+Thread.currentThread().getId());  
          20.         Log.d(TAG,"Activity name:"+Thread.currentThread().getName());  
          21.           
          22.     }  
          23.     Runnable r = new Runnable()  
          24.     {  
          25.         public void run()  
          26.         {  
          27.             Log.d(TAG,"Handler id:"+Thread.currentThread().getId());  
          28.             Log.d(TAG,"Handler name:"+Thread.currentThread().getName());  
          29.             try {  
          30.                 Thread.sleep(5000);  
          31.             } catch (InterruptedException e) {  
          32.                 // TODO Auto-generated catch block  
          33.                 e.printStackTrace();  
          34.             }  
          35.         }  
          36.     };  
          37. }  

           

          運行結(jié)果:

          證明是同一個線程的兩個依據(jù):

          ①Activity的id或name和Handler的id或name是同樣的

          ②我設(shè)置了

           handler.post(r);
           setContentView(R.layout.main);

          也就是,如果執(zhí)行后馬上顯示文本信息,那么可以證明它們不在同一個線程,但是實際情況是要先執(zhí)行了handler后5秒,才顯示文本信息,說明它們在同一線程



           

           

          如果將代碼改為

          Java代碼  收藏代碼
          1. //handler.post(r);  
          2. setContentView(R.layout.main);  
          3. Thread t = new Thread(r);  
          4. t.start();  

           再次執(zhí)行,運行結(jié)果如下,通過start啟動線程,它們不在同一個線程中

           

           

          ----------------------------------------------------------------------------------------------------------------

          Looper即循環(huán)的從隊列當(dāng)中取得消息的功能,如果在線程中使用Looper
          那么,就會循環(huán)的從線程隊列當(dāng)中取得消息并處理,如果隊列當(dāng)中沒有消息的話
          ,線程就進入了休眠狀態(tài)

          Looper很少自己創(chuàng)建,在Android中給出了HandlerThread類,并且具有循環(huán)取得并處理消息的功能

           

          下面來實現(xiàn)這種Activity和Handler分別在兩個線程中執(zhí)行,實現(xiàn)真正的異步處理

          Java代碼  收藏代碼
          1. package org.hualang.handlertest;  
          2.   
          3. import android.app.Activity;  
          4. import android.os.Bundle;  
          5. import android.os.Handler;  
          6. import android.os.HandlerThread;  
          7. import android.os.Looper;  
          8. import android.os.Message;  
          9. import android.util.Log;  
          10.   
          11. public class HandlerTest4 extends Activity {  
          12.     /** Called when the activity is first created. */  
          13.     @Override  
          14.     public void onCreate(Bundle savedInstanceState) {  
          15.         super.onCreate(savedInstanceState);  
          16.         setContentView(R.layout.main);  
          17.         Log.d("System.out","Activity所在線程的id:"+Thread.currentThread().getId());  
          18.         /** 
          19.          * 生成一個HandlerThread對象,實現(xiàn)了使用Looper來處理消息隊列的功能 
          20.          * 這個類由Android應(yīng)用程序框架提供 
          21.          */  
          22.         HandlerThread handlerThread = new HandlerThread("handlerThread");  
          23.         handlerThread.start();  
          24.         MyHandler handler = new MyHandler(handlerThread.getLooper());  
          25.         Message msg = handler.obtainMessage();  
          26.         /** 
          27.          * 將Message對象發(fā)送到目標對象 
          28.          * 所謂的目標對象,就是生成該msg對象的handler對象 
          29.          */  
          30.         msg.sendToTarget();  
          31.     }  
          32.     class MyHandler extends Handler  
          33.     {  
          34.         public MyHandler()  
          35.         {     
          36.         }  
          37.         public MyHandler(Looper looper)  
          38.         {  
          39.             super(looper);  
          40.         }  
          41.         public void handleMessage(Message msg)  
          42.         {  
          43.             Log.d("System.out", "handler所在線程的id:"+Thread.currentThread().getId());  
          44.         }  
          45.     }  
          46. }  

           

          運行結(jié)果:



           

          可以看到,Activity和Handler是在兩個不同的線程中執(zhí)行的,這樣就是實現(xiàn)了真正的異步處理

          1、首先創(chuàng)建一個HandlerThread對象,這個HandlerThread類實現(xiàn)了循環(huán)的取得消息并處理

          2、用start方法啟動一個新線程

          3、創(chuàng)建MyHandler類,里面?zhèn)鬟f的參數(shù)即Looper方法所獲得的可以循環(huán)在隊列中取得的消息

          4、MyHandler類調(diào)用的是帶參數(shù)Looper的構(gòu)造方法,并且實現(xiàn)了handlerMessage方法

          5、獲取一個Message對象

          6、將這個對象發(fā)送到生成該msg對象的handler對象,從而執(zhí)行了handleMessage方法

           

          -----------------------------------------------------------------------------------------------------

          最后,將說一下Message里傳送的數(shù)據(jù)的使用,這里的msg對象可以使用arg1,arg2或者obj

          arg1 and arg2 are lower-cost alternatives to using setData() if you only need to store a few integer values. 也就是相對于setData()方法,如果你僅僅保存一些簡單的整形數(shù)的話,arg1,arg2對資源的要求較低,而setData()方法一般用于傳遞 大量數(shù)據(jù)的時候會用到

           

          如果是msg.obj,那么可以這樣用

          msg.obj = "Welcome to china";

          然后在handleMessage()方法中用

          String str = (String)msg.obj;來獲得傳遞的值

           

          如果使用getData()方法的話,需要用到Bundle對象來傳遞,下面用個例子來說明

          Java代碼  收藏代碼
          1. Bundle b = new Bundle();  
          2. b.putInt("age", 22);  
          3. b.putString("name", "loulijun");  
          4. msg.setData(b);  
          5. msg.sendToTarget();  

           

          上面的代碼用來設(shè)置要傳遞的數(shù)據(jù)

          下面的代碼用來獲取Bundle傳遞過來的數(shù)據(jù)并且用Toast來顯示

          Java代碼  收藏代碼
          1. Bundle b = msg.getData();  
          2.             int age = b.getInt("age");  
          3.             String name = b.getString("name");  
          4.             Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);  
          5.             toast.show();  

           

          package org.hualang.handlertest;

          import android.app.Activity;
          import android.os.Bundle;
          import android.os.Handler;
          import android.os.HandlerThread;
          import android.os.Looper;
          import android.os.Message;
          import android.util.Log;
          import android.widget.Toast;

          public class HandlerTest4 extends Activity {
              /** Called when the activity is first created. */
              @Override
              public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.main);
                  Log.d("System.out","Activity所在線程的id:"+Thread.currentThread().getId());
                  /**
                   * 生成一個HandlerThread對象,實現(xiàn)了使用Looper來處理消息隊列的功能
                   * 這個類由Android應(yīng)用程序框架提供
                   */
                  HandlerThread handlerThread = new HandlerThread("handlerThread");
                  /**
                   * 使用HandlerThread的getLooper()方法之前,必須先調(diào)用該類的start()方法,否則是個null,會報錯
                   */
                  handlerThread.start();
                  MyHandler handler = new MyHandler(handlerThread.getLooper());
                  Message msg = handler.obtainMessage();
                  /**
                   * 將Message對象發(fā)送到目標對象
                   * 所謂的目標對象,就是生成該msg對象的handler對象
                   */
                  //msg.obj = "Hello world";
                  Bundle b = new Bundle();
                  b.putInt("age", 22);
                  b.putString("name", "loulijun");
                  msg.setData(b);
                  msg.sendToTarget();
              }
              class MyHandler extends Handler
              {
              public MyHandler()
              {
              }
              public MyHandler(Looper looper)
              {
              super(looper);
              }
              public void handleMessage(Message msg)
              {
              //String str = (String)msg.obj
              Bundle b = msg.getData();
              int age = b.getInt("age");
              String name = b.getString("name");
              Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);
              toast.show();
              Log.d("System.out", "handler所在線程的id:"+Thread.currentThread().getId());
              }
              }
          }

           運行結(jié)果:



           

           


          posted on 2013-04-09 09:36 姚先進 閱讀(265) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
           
          主站蜘蛛池模板: 镇远县| 尼勒克县| 云梦县| 新和县| 全州县| 萨迦县| 莱芜市| 白水县| 称多县| 泾源县| 洮南市| 玉林市| 定边县| 香格里拉县| 寻甸| 镇巴县| 景泰县| 白银市| 天峻县| 阳山县| 成安县| 兴业县| 松江区| 武强县| 岑溪市| 台安县| 开江县| 朔州市| 常宁市| 长治县| 宜阳县| 门头沟区| 济南市| 巧家县| 襄垣县| 无锡市| 高淳县| 长岭县| 涟水县| 凉城县| 阿拉善盟|