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

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

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

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

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

           

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

           



           

          handler采用的是一個消息隊列的方式,每一個handler都有一個與之關聯的消息隊列,而且是先進先出的方式執行,即:每次加入一個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.                  * 調用Handler的post方法,將要執行的線程對象添加到 
          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.     //創建Handler對象  
          47.     Handler handler = new Handler();  
          48.     /** 
          49.      * 將要執行的操作卸載寫入線程對象的run()方法當中 
          50.      */  
          51.     Runnable updateThread = new Runnable()  
          52.     {  
          53.         public void run()  
          54.         {  
          55.             System.out.println("更新線程");  
          56.             //在run方法內部,執行postXX的方法,每隔3秒會執行一次  
          57.             handler.postDelayed(updateThread, 3000);  
          58.         }  
          59.     };  
          60. }  

           

          運行結果如下:



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

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

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

           

          然后,執行postDelayed方法,由于里面設置的間隔時間,所以每3秒會調價一個handler對象到線程隊列中,并且一直執行,直到點擊“結束”按鈕,調用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.      * 使用匿名內部類來復寫hanlder當中的hanldrMessage方法 
          33.      * 這里的msg對象就是從線程部分發送過來的對象 
          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.     //線程類,該類使用的是匿名內部類的方式進行聲明  
          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操作系統提供 
          53.              * obtainMessage方法用來得到Message對象 
          54.              */  
          55.             Message msg = handler.obtainMessage();  
          56.             /** 
          57.              * Message中有個成員變量,即msg獨享的arg1參數 
          58.              * 將其值設置為i。用arg1或arg2這兩個成員變量傳遞 
          59.              * 消息,優點是系統性能消耗較少 
          60.              */  
          61.             msg.arg1 = i;  
          62.             try {  
          63.                 //當前線程休眠1秒  
          64.                 Thread.sleep(5000);  
          65.             } catch (InterruptedException e) {  
          66.                 // TODO Auto-generated catch block  
          67.                 e.printStackTrace();  
          68.             }  
          69.             /** 
          70.              * 發送一個消息,用sendMessage是將msg加入到消息 
          71.              * 隊列中。而post是將線程加入到線程隊列中 
          72.              */  
          73.             handler.sendMessage(msg);  
          74.             if( i == 100)  
          75.             {  
          76.                 /** 
          77.                  * 如果i=100的時候,就將線程對象 
          78.                  * 從handler當中移除 
          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>  

           

          運行結果:



           

           

          程序說明:

          1、當點擊按鈕后,會執行按鈕的onClick方法中的

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

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

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

          3、將i賦給Message對象的參數arg1

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

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

          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、循環執行,直到i=100,進度條隱藏,并將線程對象從線程隊列中取出






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

          上一篇博客里的對Handler的調用時通過Runnable接口來實現的,并且是通過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. }  

           

          運行結果:

          證明是同一個線程的兩個依據:

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

          ②我設置了

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

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



           

           

          如果將代碼改為

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

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

           

           

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

          Looper即循環的從隊列當中取得消息的功能,如果在線程中使用Looper
          那么,就會循環的從線程隊列當中取得消息并處理,如果隊列當中沒有消息的話
          ,線程就進入了休眠狀態

          Looper很少自己創建,在Android中給出了HandlerThread類,并且具有循環取得并處理消息的功能

           

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

          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對象,實現了使用Looper來處理消息隊列的功能 
          20.          * 這個類由Android應用程序框架提供 
          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對象發送到目標對象 
          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. }  

           

          運行結果:



           

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

          1、首先創建一個HandlerThread對象,這個HandlerThread類實現了循環的取得消息并處理

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

          3、創建MyHandler類,里面傳遞的參數即Looper方法所獲得的可以循環在隊列中取得的消息

          4、MyHandler類調用的是帶參數Looper的構造方法,并且實現了handlerMessage方法

          5、獲取一個Message對象

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

           

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

          最后,將說一下Message里傳送的數據的使用,這里的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()方法,如果你僅僅保存一些簡單的整形數的話,arg1,arg2對資源的要求較低,而setData()方法一般用于傳遞 大量數據的時候會用到

           

          如果是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();  

           

          上面的代碼用來設置要傳遞的數據

          下面的代碼用來獲取Bundle傳遞過來的數據并且用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對象,實現了使用Looper來處理消息隊列的功能
                   * 這個類由Android應用程序框架提供
                   */
                  HandlerThread handlerThread = new HandlerThread("handlerThread");
                  /**
                   * 使用HandlerThread的getLooper()方法之前,必須先調用該類的start()方法,否則是個null,會報錯
                   */
                  handlerThread.start();
                  MyHandler handler = new MyHandler(handlerThread.getLooper());
                  Message msg = handler.obtainMessage();
                  /**
                   * 將Message對象發送到目標對象
                   * 所謂的目標對象,就是生成該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());
              }
              }
          }

           運行結果:



           

           


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

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


          網站導航:
           
           
          主站蜘蛛池模板: 奈曼旗| 阳原县| 东兰县| 太仆寺旗| 甘泉县| 甘谷县| 建瓯市| 陕西省| 内丘县| 芜湖市| 三门县| 仙居县| 金门县| 朝阳县| 陈巴尔虎旗| 荆门市| 登封市| 合肥市| 南皮县| 陇西县| 油尖旺区| 大厂| 贵港市| 淮南市| 普安县| 绥滨县| 台北县| 封开县| 侯马市| 浦北县| 温泉县| 金乡县| 柳河县| 齐河县| 云安县| 开阳县| 文山县| 临潭县| 乌拉特中旗| 长泰县| 湖州市|