首页 > 代码库 > Handler的认识与使用一

Handler的认识与使用一

目录:

 

基础知识:

 

1、Android的进程与线程模型

2、Android的UI主线程(或叫线程安全问题)

涉及知识点:

Handler的介绍

Handler使用方式一:子线程处理事务(后台干活),干完活后,在子线程中通过handler发消息,通知UI线程更新UI控件,由主线程中的handler的handleMessage处理UI更新动作。

Handler的使用方式二:Handler + HandlerThread

 

 

 

基础知识:

1、Android的进程与线程模型

    Android的每个应用程序都运行在一个拥有独立用户ID的用户进程里,以保证每个应用的数据、程序都是互相隔离的。

    参考:http://www.cnblogs.com/Hendy2014/articles/android_process_model.html

2、Android的UI主线程(或叫线程安全问题)

    什么是UI主线程? 什么叫Android的单线程模型?什么叫Android的线程安全问题?

    参考:

     http://www.cnblogs.com/yaozhenfa/p/np_android_Handler.html

     http://www.cnblogs.com/dawei/archive/2011/04/09/2010259.html

 

涉及知识点:
  android.os.Handler 、 android.os.Handler.Callback
  Looper、
  Thread、Runnable
  Message、Message queue

 

Handler的介绍

    由于前述Android的进程模型与线程模型(UI主线程,线程安全问题),Android提供了一些解决机制,Handler就是其中一种。

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

    Handler有两种消息方式,来解决线程间通信和操作问题,一是Handler.sendMessage()系列方法,二是Handler.post(Runnble)系列方法,但深入Handler源码,会发现是一回事。

 

Handler使用方式一:子线程处理事务(后台干活),干完活后,在子线程中通过handler发消息,通知UI线程更新UI控件,由主线程中的handler的handleMessage处理UI更新动作。

 

,handler的post是异步操作的
,两个队列,post线程对列,message消息队列

技术分享

                   Handler使用方式一 模型图

public class HandlerTestActivity extends Activity {    private TextView tv;    private static final int UPDATE = 0;    private Handler handler = new Handler() {         @Override        public void handleMessage(Message msg) {            // TODO 接收消息并且去更新UI线程上的控件内容            if (msg.what == UPDATE) {                // Bundle b = msg.getData();                // tv.setText(b.getString("num"));                tv.setText(String.valueOf(msg.obj));            }            super.handleMessage(msg);        }    };     /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        tv = (TextView) findViewById(R.id.tv);         new Thread() {            @Override            public void run() {                // TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值                try {                    for (int i = 0; i < 100; i++) {                        Thread.sleep(500);                        Message msg = new Message();                        msg.what = UPDATE;                        // Bundle b = new Bundle();                        // b.putString("num", "更新后的值:" + i);                        // msg.setData(b);                        msg.obj = "更新后的值:" + i;                        handler.sendMessage(msg);                    }                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }.start();    } }

  

另外,使用post()方式的示例

package android.handler;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class HandlerTest extends Activity {    /** Called when the activity is first created. */	private Button startButton;	private Button endButton;	    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        //根据id获得控件对象        startButton = (Button)findViewById(R.id.startButton);        endButton = (Button)findViewById(R.id.endButton);        //为控件设置监听器        startButton.setOnClickListener(new StartButtonListener());        endButton.setOnClickListener(new EndButtonListener());    }        class StartButtonListener implements OnClickListener{		public void onClick(View v) {			//调用Handler的post()方法,将要执行的线程对象放到队列当中			handler.post(updateThread);		}    }        class EndButtonListener implements OnClickListener{		public void onClick(View v) {			//调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象			handler.removeCallbacks(updateThread);		}    	    }        //创建Handler对象    Handler handler = new Handler();    //新建一个线程对象    Runnable updateThread = new Runnable(){    	//将要执行的操作写在线程对象的run方法当中    	public void run(){    		System.out.println("updateThread");    		//调用Handler的postDelayed()方法    		//这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象    		//第一个参数是Runnable类型:将要执行的线程对象    		//第二个参数是long类型:延迟的时间,以毫秒为单位    		handler.postDelayed(updateThread, 3000);    	}    };}

 

Handler的使用方式二:Handler + HandlerThread

相当于借助封装好的HandlerThread去开启一个异步线程,它包含了自己的Looper对象,即有运行于异步线程中的MessageQueue消息机制,而创建Handler的时候,通过HandlerThread.getLooper()方法获得Looper,使用它作为handler创建的参数,让其与Handler绑定,这样,handler的消息处理(handleMessage或被post的runnable方法)便是在异步线程的handlerThread中了。

示例代码一:

public class ThreadDemo extends Activity {	private static final String TAG = "bb";      private int count = 0;      private Handler mHandler ;            private Runnable mRunnable = new Runnable() {                    public void run() {              //为了方便 查看,我们用Log打印出来              Log.e(TAG, Thread.currentThread().getId() + " " +count);              count++;  //            setTitle("" +count);              //每2秒执行一次              mHandler.postDelayed(mRunnable, 2000);          }                };      @Override      public void onCreate(Bundle savedInstanceState) {      	Log.e(TAG, "Main id    "+Thread.currentThread().getId() + " " +count);          super.onCreate(savedInstanceState);          setContentView(R.layout.main);           //通过Handler启动线程          HandlerThread handlerThread = new HandlerThread("threadone");        handlerThread.start();        mHandler =  new Handler(handlerThread.getLooper());        mHandler.post(mRunnable);                      }      @Override      protected void onDestroy() {          //将线程与当前handler解除        mHandler.removeCallbacks(mRunnable);          super.onDestroy();      }  }

 

创建handler时,如未为其指定looper对象(new Handler(Looper)或setLooper(Looper)),则handler默认使用创建它的线程的looper,则handler的消息处理最终也运行在创建它的线程当中(post()中的runnable对象,sendMessage()后的handleMessage()代码),为证这一点,下面的例子,使用UI主线程创建handler,则其post()中的runnable对象,sendMessage()后的handleMessage()代码都将运行在UI主线程当中。

示例一:

public class ThreadDemo extends Activity {	private static final String TAG = "bb";      private int count = 0;      private Handler mHandler ;            private Runnable mRunnable = new Runnable() {                    public void run() {              //为了方便 查看,我们用Log打印出来              Log.e(TAG, Thread.currentThread().getId() + " " +count);              count++;              setTitle("" +count);              //每2秒执行一次              mHandler.postDelayed(mRunnable, 2000);          }                };      @Override      public void onCreate(Bundle savedInstanceState) {      	Log.e(TAG, "Main id    "+Thread.currentThread().getId() + " " +count);          super.onCreate(savedInstanceState);          setContentView(R.layout.main);           //通过Handler启动线程          mHandler =  new Handler();        mHandler.post(mRunnable);  //mRunnable最终运行于UI主线程    }      @Override      protected void onDestroy() {          //将线程与当前handler解除绑定        //mHandler.removeCallbacks(mRunnable);          super.onDestroy();      }  }

 

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

查缺补漏一下:java线程的复习

主线程里新建Thread并start(), 同样的runnable()会打印出不同的ThreadId, start后的thread是进入线程状态机的,cpu时间片轮到该thread的时候执行,而后进入开始、运行、暂停、停止等状态机中。(线程的生命周期,还记得吗?)

private Runnable mRunnable = new Runnable() {                    public void run() {              //为了方便 查看,我们用Log打印出来              Log.e(TAG, Thread.currentThread().getId() + " " +count);              count++;              setTitle("" +count);              //每2秒执行一次              mHandler.postDelayed(mRunnable, 2000);          }                };  @Override      public void onCreate(Bundle savedInstanceState) {             super.onCreate(savedInstanceState);          setContentView(R.layout.main);           //通过Handler启动线程          Thread thread =  new Thread (mRunnable);	  thread.start();    }  

  

 相关博文:

http://www.cnblogs.com/youxilua/archive/2011/11/25/2263825.html

http://www.cnblogs.com/yaozhenfa/p/np_android_Handler.html

 

其它参考:

Pro android 3 这本书,里面描述的Handler 说得非常的细致。

 

Handler的认识与使用一