Handler使用

一、Handler的定义:


          主要接受子 线程 发送的数据, 并用此数据配合主线程更新UI.

          解释: 当应用程序启动时, Android 首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI 控件 ,进行事件分发, 比如说, 你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。  如果此时需要一个耗时的操作,例如: 联网读取数据,    或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,,会收到Android系统的一个错误提示  "强制关闭".  这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不 安全 的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的. 这个时候,Handler就出现了.,来解决这个复杂的问题 ,    由于Handler运行在主线程中(UI线程中),  它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据)  , 把这些消息放入主线程队列中,配合主线程进行更新UI。

二、Handler一些特点


        handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
        它有两个作用: (1):  安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行
      
        Handler中分发消息的一些方法
        post(Runnable)
        postAtTime(Runnable,long)
        postDelayed(Runnable long)
        sendEmptyMessage(int)
        sendMessage(Message)
        sendMessageAtTime(Message,long)
        sendMessageDelayed(Message,long)

        以上post类方法允许你排列一个Runnable对象到主线程队列中,
        sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.

三、Handler实例


      (1) 子类需要继承Hendler类,并重写handleMessage(Message msg) 方法, 用于接受线程数据

      以下为一个实例,它实现的功能为 : 通过线程修改界面Button的内容

[java]  view plain  copy
  1. public class MyHandlerActivity extends Activity {  
  2.     Button button;  
  3.     MyHandler myHandler;  
  4.   
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.handlertest);  
  8.   
  9.         button = (Button) findViewById(R.id.button);  
  10.         myHandler = new MyHandler();  
  11.         // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据  
  12.         // Handler有两个作用, (1) : 定时执行Message和Runnalbe 对象  
  13.         // (2): 让一个动作,在不同的线程中执行.  
  14.   
  15.         // 它安排消息,用以下方法  
  16.         // post(Runnable)  
  17.         // postAtTime(Runnable,long)  
  18.         // postDelayed(Runnable,long)  
  19.         // sendEmptyMessage(int)  
  20.         // sendMessage(Message);  
  21.         // sendMessageAtTime(Message,long)  
  22.         // sendMessageDelayed(Message,long)  
  23.          
  24.         // 以上方法以 post开头的允许你处理Runnable对象  
  25.         //sendMessage()允许你处理Message对象(Message里可以包含数据,)  
  26.   
  27.         MyThread m = new MyThread();  
  28.         new Thread(m).start();  
  29.     }  
  30.   
  31.     /** 
  32.      * 接受消息,处理消息 ,此Handler会与当前主线程一块运行 
  33.      * */  
  34.   
  35.     class MyHandler extends Handler {  
  36.         public MyHandler() {  
  37.         }  
  38.   
  39.         public MyHandler(Looper L) {  
  40.             super(L);  
  41.         }  
  42.   
  43.         // 子类必须重写此方法,接受数据  
  44.         @Override  
  45.         public void handleMessage(Message msg) {  
  46.             // TODO Auto-generated method stub  
  47.             Log.d("MyHandler""handleMessage......");  
  48.             super.handleMessage(msg);  
  49.             // 此处可以更新UI  
  50.             Bundle b = msg.getData();  
  51.             String color = b.getString("color");  
  52.             MyHandlerActivity.this.button.append(color);  
  53.   
  54.         }  
  55.     }  
  56.   
  57.     class MyThread implements Runnable {  
  58.         public void run() {  
  59.   
  60.             try {  
  61.                 Thread.sleep(10000);  
  62.             } catch (InterruptedException e) {  
  63.                 // TODO Auto-generated catch block  
  64.                 e.printStackTrace();  
  65.             }  
  66.   
  67.             Log.d("thread.......""mThread........");  
  68.             Message msg = new Message();  
  69.             Bundle b = new Bundle();// 存放数据  
  70.             b.putString("color""我的");  
  71.             msg.setData(b);  
  72.   
  73.             MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler发送消息,更新UI  
  74.   
  75.         }  
  76.     }  
  77.   
  78. }  

四、handler使用Message

1.定义一个Handler

2.重写消息处理函数

3.发送消息

[java]  view plain  copy
  1. //创建简单的View  
  2.  import android.content.Context;    
  3.  import android.graphics.Canvas;    
  4.  import android.graphics.Color;    
  5.  import android.graphics.Paint;    
  6.  import android.graphics.Point;    
  7.  import android.graphics.drawable.Drawable;    
  8.  import android.view.View;    
  9.      
  10.  public class BounceView extends View {    
  11.      float x = 40;    
  12.          
  13.      public BounceView(Context context) {     
  14.           super(context);     
  15.      }     
  16.      
  17.      @Override     
  18.      protected void onDraw(Canvas canvas) {     
  19.          x+=10;    
  20.          Paint mPaint = new Paint();    
  21.          mPaint.setAntiAlias(true);    
  22.          mPaint.setColor(Color.GREEN);    
  23.          canvas.drawCircle(x, 4040, mPaint);    
  24.      }    
  25.  }    
  26.   
  27. //创建Activity  
  28.  import android.app.Activity;    
  29.  import android.content.Context;    
  30.  import android.graphics.Canvas;    
  31.  import android.graphics.Color;    
  32.  import android.graphics.Paint;    
  33.  import android.os.Bundle;    
  34.  import android.os.Handler;    
  35.  import android.os.Message;    
  36.  import android.view.View;    
  37.  import android.view.Window;    
  38.      
  39.  public class TestHandler extends Activity {    
  40.       protected static final int GUIUPDATEIDENTIFIER = 0x101;     
  41.           
  42.       Thread myRefreshThread = null;     
  43.       BounceView myBounceView = null;     
  44.       //1.定义一个Handler(一般更新View)  
  45.       Handler myHandler = new Handler() {    
  46.            //2.重写消息处理函数  
  47.            public void handleMessage(Message msg) {     
  48.                 switch (msg.what) {     
  49.                      //判断发送的消息  
  50.                      case TestHandler.GUIUPDATEIDENTIFIER:     
  51.                           //更新View  
  52.                           myBounceView.invalidate();    
  53.                           break;     
  54.                 }     
  55.                 super.handleMessage(msg);     
  56.            }     
  57.       };    
  58.       public void onCreate(Bundle savedInstanceState) {     
  59.            super.onCreate(savedInstanceState);     
  60.            this.requestWindowFeature(Window.FEATURE_NO_TITLE);     
  61.       
  62.            this.myBounceView = new BounceView(this);    
  63.            this.setContentView(this.myBounceView);     
  64.            new Thread(new myThread()).start();    
  65.       }     
  66.       
  67.       class myThread implements Runnable {     
  68.            public void run() {    
  69.                 while (!Thread.currentThread().isInterrupted()) {      
  70.                      //3.发送消息  
  71.                      Message message = new Message();   
  72.                      //发送消息与处理函数里一致    
  73.                      message.what = TestHandler.GUIUPDATEIDENTIFIER;     
  74.                      //内部类调用外部类的变量  
  75.                      TestHandler.this.myHandler.sendMessage(message);    
  76.    
  77.                      try {     
  78.                           Thread.sleep(100);      
  79.                      } catch (InterruptedException e) {     
  80.                           Thread.currentThread().interrupt();     
  81.                      }     
  82.                 }     
  83.            }     
  84.       }     
  85.  }  

五、利用handler.post()更新UI

1.创建一个Handler 

2.调用Handler.post(Runnable r)方法 

3.Runnable运行在UI所在线程,所以可以直接调用View.invalidate()


[java]  view plain  copy
  1. import android.app.Activity;    
  2. import android.content.Context;    
  3. import android.graphics.Canvas;    
  4. import android.graphics.Color;    
  5. import android.graphics.Paint;    
  6. import android.os.Bundle;    
  7. import android.os.Handler;    
  8. import android.view.View;    
  9.     
  10. public class TestHandler extends Activity {    
  11.     private MyView myView;    
  12.     private Handler mHandler;    
  13.     public void onCreate(Bundle savedInstanceState) {    
  14.         super.onCreate(savedInstanceState);    
  15.         myView = new MyView(this);    
  16.         //创建一个Handler  
  17.         mHandler = new Handler();  
  18.         //调用Handler.post(Runnable r)方法  
  19.         mHandler.post(new Runnable(){    
  20.             @Override    
  21.             public void run() {    
  22.                 //直接调用View.invalidate(),更新组件  
  23.                 myView.invalidate();    
  24.                 //延迟5毫秒后执行线程  
  25.                 mHandler.postDelayed(this5);    
  26.             }    
  27.          });    
  28.         setContentView(myView);    
  29.     }    
  30.         
  31.     class MyView extends View{    
  32.         private float x = 0f;    
  33.         public MyView(Context context) {    
  34.             super(context);    
  35.                 
  36.     }    
  37.         protected void onDraw(Canvas canvas) {    
  38.             super.onDraw(canvas);    
  39.             x+=1;    
  40.             Paint mPaint = new Paint();    
  41.             mPaint.setColor(Color.BLUE);    
  42.             canvas.drawRect(x, 40, x+4080, mPaint);    
  43.         }    
  44.             
  45.     }    

六、在线程里直接更新UI

[java]  view plain  copy
  1. //在新线程里更新UI,可以直接使用postInvalidate()   
  2.   
  3. public void onCreate(Bundle savedInstanceState) {        
  4.        super.onCreate(savedInstanceState);        
  5.        this.requestWindowFeature(Window.FEATURE_NO_TITLE);        
  6.        
  7.        myView = new MyView(this);    
  8.        this.setContentView(this.myView);        
  9.        new Thread(new myThread()).start();       
  10. }        
  11.       
  12. class myThread implements Runnable {        
  13.       public void run() {       
  14.           while (!Thread.currentThread().isInterrupted()) {        
  15.              try {    
  16.                    //更新UI  
  17.                    myView.postInvalidate();     
  18.                    Thread.sleep(100);         
  19.               } catch (InterruptedException e) {        
  20.                    Thread.currentThread().interrupt();        
  21.               }        
  22.           }        
  23.       }        
  24. }   

七、Android中的Handler机制

直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错 误:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.翻译过来就是:只有创建这个控件的线程才能去更新该控件的内容。
    所有的UI线程要去负责View的创建并且维护它,例如更新冒个TextView的显示,都必须在主线程中去做,我们不能直接在UI线程中去创建子线程,要利用消息机制:handler,如下就是handler的简单工作原理图:

既然android给我们提供了Handler机制来解决这样的问题,请看如下代码:

[java]  view plain  copy
  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.     @Override  
  20.     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.             @Override  
  27.             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. }  

八、Handler实例讲解

1、Handler简介

Handler 为Android操作系统中的线程通信工具,包为android.os.Handler。

与Handler绑定的有两个队列,一个为消息队列,另一个为线程队列。Handler可以通过这两个队列来分别:

发送、接受、处理消息–消息队列;

启动、结束、休眠线程–线程队列;

Android OS中,一个进程被创建之后,主线程(可理解为当前Activity)创建一个消息队列,这个消息队列维护所有顶层应用对象(Activities, Broadcast receivers等)以及主线程创建的窗口。你可以在主线程中创建新的线程,这些新的线程都通过Handler与主线程进行通信。通信通过新线程调用Handler的post()方法和sendMessage()方法实现,分别对应功能:

post() 将一个线程加入线程队列;

sendMessage() 发送一个消息对象到消息队列;

当然,post()方法还有一些变体,比如postDelayed()、postAtTime()分别用来延迟发送、定时发送;

消息的处理,在主线程的Handler对象中进行;具体处理过程,需要在new Handler对象时使用匿名内部类重写Handler的handleMessage(Message msg)方法;

从消息队列中获取消息。

线程加入线程队列可以在主线程中也可以在子线程中进行,但都要通过主线程的Handler对象调用post()。

2、Handler实例

与ProgressBar结合的例子:


package mars.barhandler;    
    
import android.app.Activity;    
import android.os.Bundle;    
import android.os.Handler;    
import android.os.Message;    
import android.view.View;    
import android.view.View.OnClickListener;    
import android.widget.Button;    
import android.widget.ProgressBar;    
    
public  class TestBarHandler  extends Activity {    
         /** Called when the activity is first created. */    
         //声明控件变量    
        ProgressBar bar =  null;    
        Button startButton =  null;    
        @Override    
         public  void onCreate(Bundle savedInstanceState) {    
                 super.onCreate(savedInstanceState);    
                setContentView(R.layout.main);    
                 //根据控件的ID得到代表控件的对象,并为按钮设置监听器    
                bar = (ProgressBar)findViewById(R.id.bar);    
                startButton = (Button)findViewById(R.id.startButton);    
                startButton.setOnClickListener( new ButtonListener());    
        }    
         //当点击startButton按钮时,就会执行ButtonListener的onClick方法    
         class ButtonListener  implements OnClickListener{    
    
                 public  void onClick(View v) {    
                         // TODO Auto-generated method stub    
                        bar.setVisibility(View.VISIBLE);    
                        updateBarHandler.post(updateThread);    
                }    
                    
        }    
         //使用匿名内部类来复写Handler当中的handleMessage方法    
        Handler updateBarHandler =  new Handler(){    
    
                @Override    
                 public  void handleMessage(Message msg) {    
                        bar.setProgress(msg.arg1);    
                        Bundle bundle = msg.getData();    
                        updateBarHandler.post(updateThread);    
                        System.out.println( "test---->" + bundle.getString( "test"));    
                }    
                    
        };    
         //线程类,该类使用匿名内部类的方式进行声明    
        Runnable updateThread =  new Runnable(){    
                 int i = 0 ;    
                 public  void run() {    
                        System.out.println( "Begin Thread" + i);    
                        i = i + 10 ;    
                         //得到一个消息对象,Message类是有Android操作系统提供    
                        Message msg = updateBarHandler.obtainMessage();    
                            
                         //将msg对象的arg1参数的值设置为i,用arg1和arg2这两个成员变量传递消息,优点是系统性能消耗较少    
                        msg.arg1 = i ;    
                        Bundle bundle =  new Bundle();    
                        bundle.putString( "test""test bundle");    
                        msg.setData(bundle);    
                         try {    
                                 //设置当前显示睡眠1秒    
                                Thread.sleep(1000);    
                        }  catch (InterruptedException e) {    
                                 // TODO Auto-generated catch block    
                                e.printStackTrace();    
                        }    
                         //将msg对象加入到消息队列当中    
                         if( i > 100){    
                                 //如果当i的值为100时,就将线程对象从handler当中移除    
                                updateBarHandler.removeCallbacks(updateThread);    
                                System.out.println( ">>>>>>");    
                        } else{    
                                updateBarHandler.sendMessage(msg);    
                                System.out.println( "<<<<<<");    
                        }    
                }    
        };    
         class MyThread  extends Thread{    
                 public  void run(){    
                            
                }    
        }    
            
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值