JAVA线程之六:线程的通信(以安卓定时器实验为例)

        当应用程序启动时,Android首先会开启一个主线程(也就是UI线程) ,主线程管理界面中的UI控件,进行事件分发。如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,如果你放在主线程中的话,界面会出现假死现象。如果5秒钟还没有完成的话,会收到Android系统的一个错误提示“强制关闭”。

        所以我们需要把这些耗时的操作,放在一个子线程中。这个时候,Handler就出现了。由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的数据(子线程用sendMessage()方法传递Message对象,把这些消息放入主线程队列中,配合主线程进行更新UI)。

(1)Handler一些特点

        handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用:A,安排消息或Runnable (消息和Runnable可能同时用到)在某个主线程中某个地方执行;B,安排一个动作在不同的线程中执行。
        Handler中分发消息的一些方法:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable long);sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。以上post类方法允许你排列一个Runnable对象到主线程队列,SendMessage类方法允许你安排一个带数据的Message对象到队列中,等待更新。

(2)子类需要继承Hendler类,并重写handleMessage(Message msg) 方法,用于接受线程数据。实例,通过线程定时修改界面Button的名称。 

package com.example.helloworld;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
import android.os.Handler;  //必须
import android.os.Message;  //必须
import android.util.Log;

public class MainActivity extends Activity {
	private final String TAG = "ThreadTest";
	Button button;
	MyHandler myHandler;
    
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button)findViewById(R.id.test);
        myHandler = new MyHandler();
        
        Thread myThread = new Thread(new MyThread());   
        myThread.start();    
    }
    
    class MyHandler extends Handler{   //主线程自己的handler
    	public void handleMessage(Message msg){    //重写自己的handleMessage函数
    		super.handleMessage(msg);
    		Bundle b = msg.getData();       //通过Bundle结构传数据
    		String color = b.getString("color");     //获得key对应的值
    		MainActivity.this.button.append(color);   //将字符串添加至BUTTON名的末尾
    	}
    }

    class MyThread implements Runnable{   
    	public void run(){
    		Message msg = new Message();   //新建msg
    		Bundle b = new Bundle();       //新建Bundle
    		b.putString("color","我的");    //将值赋给Bundle中特定的key
    		msg.setData(b);
 
    		try{
    			Thread.sleep(5000);
    		}catch(InterruptedException e){
    			e.printStackTrace();
    		}
    		
    		Log.i(TAG,"run once ");
    		MainActivity.this.myHandler.sendMessage(msg);   //发送消息给主线程
    	}
    }
}

       需要注意的是:android.widget.Button是android.widget.TextView的子类,所以可使用append。

(3)以上是用的线程sleep来完成定时的功能,另一种方法可以用postDelayed来实现同样的功能,对应的线程使用可以改个形式。使用方法:
       A,首先创建一个Handler对象,Handler handler=new Handler();
       B,然后创建一个Runnable对象,
               Runnable runnable=new Runnable(){
                     public void run() {
                          // TODO Auto-generated method stub
                         //要做的事情,这里可以再次调用此Runnable对象,在线程中设定2秒后再执行自己,从而实现每两秒实现一次的定时器操作
                         handler.postDelayed(this, 2000);
                      }
                };
        C,如果是单独使用handler.postDelayed(runnable, 2000);方法,则是两秒后调用此Runnable对象,仅仅执行一次。
        D,如果用完了想要关闭此定时器,可以handler.removeCallbacks(runnable);

 (4)把实例2中的程序改成(3)方法来实现,代码如下:

public class MainActivity extends Activity {
	private final String TAG = "ThreadTest";
	Button button;
	MyHandler myHandler;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button = (Button)findViewById(R.id.test);
        myHandler = new MyHandler();       
        myHandler.postDelayed(r,5000);   //启动线程,5秒后。改用它的延时来代替sleep
    }
    
    class MyHandler extends Handler{
    	public void handleMessage(Message msg){
    		super.handleMessage(msg);
    		Bundle b = msg.getData();
    		String color = b.getString("color");
    		button.append(color);
    	}
    }

    Runnable r = new Runnable(){
    	public void run(){
    		Message msg = new Message();
    		Bundle b = new Bundle();
    		b.putString("color","我的");
    		msg.setData(b);
		
    		Log.i(TAG,"run once ");
    		myHandler.sendMessage(msg);   //发消息给主线程
    		myHandler.postDelayed(r,5000);   //有这句该程序就是个5秒的循环,没有这句就启动5秒后运行一次线程就结束
    		//myHandler.removeCallbacks(r);   //运行到一定阶段可以关闭定时器。r用完后才会remove
    	}
    };   //注意整个是赋值语句,并不是函数,所以有分号
}


参考原文:http://www.pin5i.com/showtopic-android-handler.html

参考原文:http://blog.csdn.net/a734797702/article/details/7634267

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值