Handler线程间通讯

  1 package com.hixin.appexplorer;
  2 
  3 import java.util.List;
  4 
  5 import android.app.Activity;
  6 import android.app.ProgressDialog;
  7 import android.content.Context;
  8 import android.content.pm.PackageInfo;
  9 import android.content.pm.PackageManager;
 10 import android.os.Bundle;
 11 import android.os.Handler;
 12 import android.os.Message;
 13 import android.view.LayoutInflater;
 14 import android.view.View;
 15 import android.view.ViewGroup;
 16 import android.view.Window;
 17 import android.view.WindowManager;
 18 import android.widget.BaseAdapter;
 19 import android.widget.GridView;
 20 import android.widget.ImageView;
 21 import android.widget.TextView;
 22 
 23 public class MainActivity extends Activity implements Runnable {
 24 
 25     GridView gv;
 26     private List<PackageInfo> packageInfos;
 27     private ProgressDialog pd;
 28     private Handler mHandler = new Handler() {
 29         @Override
 30         public void handleMessage(Message msg) {
 31             // TODO Auto-generated method stub
 32             super.handleMessage(msg);
 33             gv.setAdapter(new GridViewAdapter(MainActivity.this));
 34             pd.dismiss();
 35             setProgressBarIndeterminateVisibility(false);
 36         }
 37         
 38     };
 39     @Override
 40     protected void onCreate(Bundle savedInstanceState) {
 41         super.onCreate(savedInstanceState);
 42     //    requestWindowFeature(Window.FEATURE_NO_TITLE);
 43         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
 44         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
 45         setContentView(R.layout.show_app_grid);
 46         
 47         gv = (GridView)this.findViewById(R.id.gv_apps);
 48         pd = ProgressDialog.show(this,"请稍候...", "正在搜索你所安装的应用程序",true,false);
 49         setProgressBarIndeterminateVisibility(true);
 50         Thread t = new Thread(this);
 51         t.start();
 52         }
 53     
 54     @Override
 55     public void run() {
 56         // TODO Auto-generated method stub
 57         packageInfos = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
 58         try {
 59             Thread.sleep(2000);
 60         } catch (InterruptedException e) {
 61             // TODO Auto-generated catch block
 62             e.printStackTrace();
 63         }
 64         mHandler.sendEmptyMessage(0);
 65     }
 66     
 67     
 68     class GridViewAdapter extends BaseAdapter{
 69 
 70         LayoutInflater inflater;
 71         public GridViewAdapter(Context context) {
 72             inflater = LayoutInflater.from(context);
 73         }
 74         @Override
 75         public int getCount() {
 76             // TODO Auto-generated method stub
 77             return packageInfos.size();
 78         }
 79 
 80         @Override
 81         public Object getItem(int position) {
 82             // TODO Auto-generated method stub
 83             return packageInfos.get(position);
 84         }
 85 
 86         @Override
 87         public long getItemId(int position) {
 88             // TODO Auto-generated method stub
 89             return position;
 90         }
 91 
 92         @Override
 93         public View getView(int position, View convertView, ViewGroup parent) {
 94             // TODO Auto-generated method stub
 95         
 96                 View view = inflater.inflate(R.layout.gv_item, null);
 97                 TextView tv = (TextView)view.findViewById(R.id.gv_item_appname);
 98                 ImageView iv = (ImageView)view.findViewById(R.id.gv_item_icon);
 99                 tv.setText(packageInfos.get(position).applicationInfo.loadLabel(getPackageManager()));
100                 iv.setImageDrawable(packageInfos.get(position).applicationInfo.loadIcon(getPackageManager()));
101             
102             return view;
103         }
104         
105     }
106     
107 }
108 
109     

 

当须要显示的项目不少,会形成很大的延迟。这时候屏幕会一直黑屏。给用户很很差的体验。应该在获取信息的时候,显示一些进度信息给用户看,增长用户体验。html

程序在期间获取安装程序信息,主界面上显示进度条,当信息获取完毕以后(获取信息在新线程里执行),发送一条消息通知主线程,主线程关掉进度条,加载列表。java

 

基本概念android

Looper:每个线程均可以产生一个Looper,用来管理线程的Message,Looper对象会创建一个MessgaeQueue数据结构来存放message。安全

Handler:与Looper沟通的对象,能够push消息或者runnable对象到MessgaeQueue,也能够从MessageQueue获得消息。数据结构

线程A的Handler对象引用能够传递给别的线程,让别的线程B或C等能送消息来给线程A。app

线程A的Message Queue里的消息,只有线程A所属的对象能够处理。ide

注意:Android里没有global的MessageQueue,不一样进程(或APK之间)不能经过MessageQueue交换消息。函数

本例中线程A就是UI线程,线程B就是新建的处理线程oop

 

ps:handler.obtainMessage()理解post

在handler.obtainMessage()的参数是这样写的:
Message android.os.Handler.obtainMessage(int what, int arg1, int arg2, Object obj)

public final Message obtainMessage (int what, int arg1, int arg2, Object obj) 
Since: API Level 1 
Same as obtainMessage(), except that it also sets the what, obj, arg1,and arg2 values on the returned Message.

Parameters
what  Value to assign to the returned Message.what field. 
arg1  Value to assign to the returned Message.arg1 field. 
arg2  Value to assign to the returned Message.arg2 field. 
obj  Value to assign to the returned Message.obj field. 

而Handler中obtainMessage与new Message的区别:

obtainmessage()是从消息池中拿来一个msg 不须要另开辟空间new

new须要从新申请,效率低,obtianmessage能够循环利用;

 

 1 //use Handler.obtainMessage(),instead of msg = new Message();   
 2 //because if there is already an Message object,that not be used by    
 3 //any one ,the system will hand use that object,so you don't have to    
 4 //create and object and allocate memory.   
 5 //it  is also another example of object recycling and reusing in android.   
 6     Message msg = mHandler.obtainMessage();  
 7     msg.what = UPDATE_LISTVIEW;  
 8     msg.obj = current + "/" + total + "songs";  
 9     //this method is called from worker Thread,so we cannot update UI from here.   
10     msg.sendToTarget();  

 

 
在看下面代码:
1 Message msg = handler.obtainMessage();  
2                         msg.arg1 = i;  
3                         msg.sendToTarget();   
4   
5   
6 Message msg=new Message();  
7     msg.arg1=i;  
8     handler.sendMessage(msg);  
第一种写法是message 从handler 类获取,从而能够直接向该handler 对象发送消息,第二种写法是直接调用 handler 的发送消息方法发送消息。
 
 

Handler相关说明:

解释:安卓的UI线程(即OnCreate函数建立的线程)是线程非安全的。也就是说,在UI线程中,使用sleep这样的函数会致使整个线程延迟,可是咱们在安卓开发中,每每会常常遇到一些延迟比较厉害的操做,(例如经过HTTP获取数据信息)若是放在主线程中,则会影响UI界面的渲染。可是若是另外新开一个线程,则因为UI线程只能在主线程中修改,而致使没法修改主线程的UI界面。这个时候Handler就出来解决这个问题。

handler能够分发Message对象和Runnable对象到主线程中, 每一个Handler实例,都会绑定到建立他的线程中(通常是位于主线程), 也就是说Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定,所以能够利用Handler所包含的消息队列,制定一些操做的顺序。

Handler主要两大做用:

1. 提供post操做。post操做主要将Runnable对象放进主线程(UI)线程中的队列中操做。post还支持延迟操做。使用post后,Runnable是按照队列的形式逐个执行的。

2. handlerMessage操做。主要用于新开一个线程与主线程中的通讯。新开的线程执行完毕后,能够经过sendMessage给主线程发送消息,而且传递一些参数,而后主线程就能够修改UI界面了。

 

Handler提供的函数:

post类方法容许你排列一个Runnable对象到主线程队列中:

post(Runnable)

postAtTime(Runnable,long)

postDelayed(Runnable long)

sendMessage类方法, 容许你安排一个带数据的Message对象到队列中:

sendEmptyMessage(int)

sendMessage(Message)

 sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

 

应用实例:

   1,传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI

          在Android中,对于UI的操做一般须要放在主线程中进行操做。若是在子线程中有关于UI的操做,那么就须要把数据消息做为一个Message对象发送到消息队列中,而后,用Handler中的handlerMessge方法处理传过来的数据信息,并操做UI。类sendMessage(Message msg)方法实现发送消息的操做。 在初始化Handler对象时重写的handleMessage方法来接收Messgae并进行相关操做。

 2,传递Runnable对象。用于经过Handler绑定的消息队列,安排不一样操做的执行顺序。

Handler对象在进行初始化的时候,会默认的自动绑定消息队列。利用类post方法,能够将Runnable对象发送到消息队列中,按照队列的机制按顺序执行不一样的Runnable对象中的run方法。

另外,Android的CPU分配的最小单元是线程,Handler通常是在某个线程里建立的,于是Handler和Thread就是相互绑定的,一一对应。而Runnable是一个接口,Thread是Runnable的子类。因此说,他俩都算一个进程。xml文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button 
        android:id="@+id/startButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start"
        android:layout_centerInParent="true"
        />
    <Button 
        android:id="@+id/endButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="end"
        android:layout_below="@id/startButton"
        />

</RelativeLayout>
View Code

 

package com.example.androidexpriment;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;


public class MainActivity extends Activity {  
       
    private String TAG = "MainActivity";
      //声明两个按钮控件  
     private Button startButton = null;  
      private Button endButton = null;  
      @Override 
      public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
          setContentView(R.layout.activity_main);  
        //根据控件的ID获得表明控件的对象,并为这两个按钮设置相应的监听器  
        startButton = (Button)findViewById(R.id.startButton);  
        startButton.setOnClickListener(new StartButtonListener());  
        endButton = (Button)findViewById(R.id.endButton);  
        endButton.setOnClickListener(new EndButtonListener());  
        Log.i(TAG,"Activity-->" + Thread.currentThread().getId()); 
           
     }  
     class StartButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
             //调用Handler的post方法,将要执行的线程对象添加到队列当中  
            handler.post(updateThread);  
         }  
           
     }  
       
     class EndButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
            handler.removeCallbacks(updateThread);  
         }  
           
   }  
    //建立一个Handler对象  
    Handler handler  = new Handler();
    //将要执行的操做写在线程对象的run方法当中  
    Runnable updateThread =  new Runnable(){  
  
         @Override 
        public void run() {  
            Log.i(TAG,"UpdateThread");  
            Log.i(TAG,"Activity-->" + Thread.currentThread().getId()); 
             //在run方法内部,执行postDelayed或者是post方法  
            handler.postDelayed(updateThread, 3000);  
        }  
           
    };  
 } 

 

点击start后,程序的运行结果就是每隔3秒钟,就会在控制台打印一行UpdateTread。这是由于实现了Runnable接口的updateThread对象进入了空的消息队列即被当即执行run方法,而在run方法的内部,又在3000ms以后将其再次发送进入消息队列中。

注意这种方法建立Handler对象并不须要重写handlerMessage方法。

从输出结果能看出来:

   post方法虽然发送的是一个实现了Runnable接口的类对象,可是它并不是建立了一个新线程,而是执行了该对象中的run方法。也就是说,整个run中的操做和主线程处于同一个线程。这样对于那些简单的操做,彷佛并不会影响。可是对于耗时较长的操做,就会出现“假死”。为了解决这个问题,就须要使得handler绑定到一个新开启线程的消息队列上,在这个处于另外线程的上的消息队列中处理传过来的Runnable对象和消息。Runnable对象只是做为一个封装了操做的对象被传递,并未产生新线程。

下面这种写法也是能够的:

package com.example.androidexpriment;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
    
     TestThread t = null;
     private String TAG = "MainActivity";
      //声明两个按钮控件  
     private Button startButton = null;  
      private Button endButton = null;  
      @Override 
      public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
         setContentView(R.layout.activity_main);  
        //根据控件的ID获得表明控件的对象,并为这两个按钮设置相应的监听器  
        startButton = (Button)findViewById(R.id.startButton);  
        startButton.setOnClickListener(new StartButtonListener());  
        endButton = (Button)findViewById(R.id.endButton);  
        endButton.setOnClickListener(new EndButtonListener());  
        Log.i(TAG,"onCreate-->" + Thread.currentThread().getId()); 
        t= new TestThread(1);
           
     }  
     class StartButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
             //调用Handler的post方法,将要执行的线程对象添加到队列当中  
            handler.post(t);  
         }  
           
     }  
           
     class EndButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
            handler.removeCallbacks(t);  
         }  
           
   }  
    //建立一个Handler对象  
    Handler handler  = new Handler();
    
    class TestThread extends Thread{
            int prime;
            TestThread(int prime) {
                this.prime = prime;
            }
        @Override
        public void run() {
                 //在run方法内部,执行postDelayed或者是post方法  
                   handler.postDelayed(t, 3000);  
                   Log.i(TAG,"TestThread-->" + Thread.currentThread().getId()); 
            } 
        }            
 } 

 

虽然建立了一个Thread,可是并无执行Thread的start()方法。考虑到Thread和Runnable之间的关系,上面的两种代码并没有实质差异,因此logcat中甚至都没出现启动新线程的日志。

然而,若是稍加修改:加上启动方法

  class StartButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
             //调用Handler的post方法,将要执行的线程对象添加到队列当中  
            handler.post(t); 
            t.start();
         }           
     }  
         

能够明显看到,虽然启动了新线程,但post仍然能够把这个线程推到主线程里面去,线程由虚拟机自动结束。

因此,在UI线程(主线程)中:

    mHandler=new Handler();

    mHandler.post(new Runnable(){

    void run(){

       //执行代码..

     }

    });

 这个线程实际上是在UI线程以内运行的,并无新建线程。

 

    常见的新建线程的方法是:参考J2SE文档的

   一、

 class PrimeThread extends Thread {
         long minPrime;
         PrimeThread(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
  }


  • The following code would then create a thread and start it running:

     

         PrimeThread p = new PrimeThread(143);
         p.start();
    

   二、

   class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }
  • The following code would then create a thread and start it running:

     

         PrimeRun p = new PrimeRun(143);
         new Thread(p).start();
    

尽可能按照上面给出的两种方式作,不要受网上影响简单的从Threa建立,那样不能作到传递参数。

static void sleep(long millis)
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.

代码验证:

 

package com.example.androidexpriment;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;


public class MainActivity extends Activity {  
       
    private String TAG = "MainActivity";
      //声明两个按钮控件  
    private Button startButton = null;  
    private Button endButton = null; 
    TestThread t = null;
    int flag = 0;
      @Override 
      public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);  
          setContentView(R.layout.activity_main);  
        //根据控件的ID获得表明控件的对象,并为这两个按钮设置相应的监听器  
        startButton = (Button)findViewById(R.id.startButton);  
        startButton.setOnClickListener(new StartButtonListener());  
        endButton = (Button)findViewById(R.id.endButton);  
        endButton.setOnClickListener(new EndButtonListener());  
        Log.i(TAG,"onCreate-->" + Thread.currentThread().getId()); 
        
        t= new TestThread(1);
           
     }  
     class StartButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
             //调用Handler的post方法,将要执行的线程对象添加到队列当中  
             t.start();
         }  
           
     }  
       
     class EndButtonListener implements OnClickListener{  
  
         @Override 
         public void onClick(View v) {  
             handler.sendEmptyMessage(33);
             flag = 5;
         }  
           
   }  
     
     
     class TestThread extends Thread{
         int prime;
         TestThread(int prime) {
             this.prime = prime;
         }
        @Override
        public void run() {
             //在run方法内部,执行postDelayed或者是post方法             
            try {
                while(true) {
                    Log.i(TAG,"TestThread-->" + Thread.currentThread().getId()); 
                    //handler.sendEmptyMessageDelayed(22,3000);
                    Thread.sleep(3000);
                    handler.sendEmptyMessage(22);
                    if(flag  == 5)  //线程最佳的退出方法,就是自杀,也就是在线程的函数里面天然的return 出来
                        return;
                }             
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
         
     }
    //建立一个Handler对象  
    Handler handler  = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            switch(msg.what) {
                case 22:
                    Log.i(TAG,"StartButton");  
                    Log.i(TAG,"Handler-->" + Thread.currentThread().getId()); 
                    break;
                case 33:
                    Log.i(TAG,"EndButton");  
                    Log.i(TAG,"Handler-->" + Thread.currentThread().getId()); 
                    break;
            }
                    
        }
        
    };

 } 

相关文章
相关标签/搜索