Handler的用法

首先撇清一个概念:Android的单线程设计是指每个应用程序的UI线程(主线程)是单线程的,即和用户交互的界面是单线程的。但是,很显然,用户界面如果采用多线程处理效率会更高,Android为什么将UI线程限制为单线程呢?这是为了避免并发编程的复杂性,也是提高Android应用的健壮性的有效途径。

但是,主线程是单线程的,并不等于Android不支持多线程,比如两个Android应用程序之间的通讯。

Android中的Handler提供了线程之间通讯的简便手段,如下图所示:

handler

 

Android的主线程(即UI线程)内部实现了消息队列机制,即一个主线程会自动创建一个消息队列(显然也只有一个消息队列),同时创建一个读取消息队列的Looper对象。主线程的所有用户交互都通过消息队列和Looper对象来实现:当有新的消息进入消息队列时,Looper会及时读取消息并调用相应的处理逻辑(更新用户界面)。

当其他线程希望更新用户界面时,可以通过Handler提供的sendMessage方法在消息队列中放入一个消息(Message对象,可以携带大量信息),这样Looper即可以及时获取该消息,并调用Handler相应的handleMessage方法处理该消息,这样就实现了线程之间的通讯。由此可以看出,Handler在线程通讯中起到了一个枢纽作用:Handler即负责和消息队列打交道,也负责处理相应的消息,其他线程通过Handler和主线程通讯,就可以不需要考虑和主线程的竞争和同步问题,极大的简化了线程的使用。

下面的示例代码演示了一个每隔1秒显示一条消息在主界面:

 

public class MainActivity extends Activity {
	private TextView label;
	private static int UPDATE = 1;
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == 1) {
				label.setText(String.valueOf(msg.obj));
				super.handleMessage(msg);
			}
		}
	};
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		label = (TextView) findViewById(R.id.label);
 
		new Thread() {
			@Override
			public void run() {
				for (int i = 0; i < 100; i++) {
 
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
 
					Message msg = new Message();
					msg.what = UPDATE;
					msg.obj = "当前循环变量:" + i;
					handler.sendMessage(msg);
				}
			}
 
		}.start();
	}
 
}

在上面的例子中,所谓的其他线程其实主线程的子线程,下面一个例子则演示了完全不同的两个组件通过Handler实现的交互:一个Service每隔1秒产生一个随机数,然后在主线程显示出来:

ServiceDemo.java文件:

public class ServiceDemo extends Service {
 
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}
 
	private Thread workThread;
 
	@Override
	public void onCreate() {
	    super.onCreate();
	    Toast.makeText(this, "(1) onCreate()", 
	    		Toast.LENGTH_LONG).show();    
	    workThread = new Thread(null,backgroudWork,"WorkThread");
	}
 
	@Override
	public void onStart(Intent intent, int startId) {
	      super.onStart(intent, startId);
	      Toast.makeText(this, "(2) onStart()", 
	    		  Toast.LENGTH_SHORT).show();
	      if (!workThread.isAlive()){
	    	  workThread.start();
	      }
 
	}
 
	@Override
	public void onDestroy() {
	     super.onDestroy();
	     Toast.makeText(this, "(3) onDestroy()", 
	    		 Toast.LENGTH_SHORT).show();     
	     workThread.interrupt();
	}
 
	private Runnable backgroudWork = new Runnable(){
		@Override
		public void run() {
			try {
				while(!Thread.interrupted()){				
					double randomDouble = Math.random();
					MainActivity.updateGUI(randomDouble);
					Thread.sleep(1000);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	};
 
}

MainActivity.java文件:

public class MainActivity extends Activity {
	private static TextView label;
	private static int UPDATE = 1;
	protected static Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == 1) {
				label.setText(String.valueOf(msg.obj));
				super.handleMessage(msg);
			}
		}
	};
 
	public static void updateGUI(double doubleRadom){
		Message msg = new Message();
		msg.what = UPDATE;
		msg.obj = "当前随机数:" + doubleRadom;
		handler.sendMessage(msg);
	}
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		label = (TextView) findViewById(R.id.label);
 
		final Intent serviceIntent = new Intent(this, ServiceDemo.class);
		startService(serviceIntent);
	}
 
}

可以看出,为了实现在两个组件间的通讯,主要的变化是:

  • 将Handler对象定义为static类型的,便于在其他组件访问handler
  • 在主线程中实现一个静态的updateGUI方法,以便通过调用handler.sendMessage添加一个消息到消息队列中
  • 在Service的线程中,调用主线程的updateGUI并传入适当的参数

 

Handler和消息循环机制的设计很巧妙,在WEB应用和企业级应用中是否可以借鉴呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值