Handler的认识与使用一_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > Handler的认识与使用一

Handler的认识与使用一

 2015/1/8 18:20:23  Hendy2014  程序员俱乐部  我要评论(0)
  • 摘要:目录:基础知识:1、Android的进程与线程模型2、Android的UI主线程(或叫线程安全问题)涉及知识点:Handler的介绍Handler使用方式一:子线程处理事务(后台干活),干完活后,在子线程中通过handler发消息,通知UI线程更新UI控件,由主线程中的handler的handleMessage处理UI更新动作。Handler的使用方式二:Handler+HandlerThread基础知识:1
  • 标签:使用 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使用方式一模型图

                   Handler使用方式一 模型图

class="brush:java;gutter:true;">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 说得非常的细致。

 

发表评论
用户名: 匿名