博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中的消息机制:Handler消息传递机制
阅读量:5166 次
发布时间:2019-06-13

本文共 4424 字,大约阅读时间需要 14 分钟。

参考《疯狂android讲义》第2版3.5 P214

一、背景

出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的原则:只允许UI线程(亦即主线程)修改Activity中的UI组件。

当一个程序第一次启动时,Android会同时启动一条主线程,主线程主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件、屏幕绘图事件,并把相关的事件分发到相应的组件进行处理,所以主线程通常又叫做UI线程。

二、使用Handler的两种常见原因

1、只能在主UI中修改UI。但实际上,有部分UI需要在子线程中控制其修改逻辑,因此子线程需要通过handler通知主线程修改UI。这在游戏开发中尤其常见,比如需要让新启动的线程周期性的改变UI。

2、为避免ANR,应该在子线程中执行耗时较长的操作,而此操作完成后,有可能需要通知主线程修改UI。

三、基本原理及步骤

1、Handler的作用主要有2个:

(1)发送消息。

(2)获取、处理消息。

2、基本原理:为了让主线程能及时处理子线程发送的消息,显然只能通过回调的方法来实现----开发者只要重写Handler类中的方法,当新启动的线程发送消息时,消息会发送至与之关联的MessageQueue,而Handler会不断的从MessageQuere中获取并处理消息-----这将导致Handler类中处理消息的方法被回调。

3、在线程中使用Handler的基本步骤如下:

在被调用线程中完成以下内容:

(1)调用 Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。

(2)有了Looper之后,创建Handler子类的实例,重写HandlerMessage()方法,该方法负责处理来自其它线程的消息。

(3)调用Looper的loop()方法启动Looper。

注:若被调用线程是主线程类,由于系统自动为主线程创建了Looper的实例,因此第一、三步骤可省略,而只需要做第2步即可。

在调用线程中完成:

(1)创建nessage,并填充内容。

(2)使用被调用类创建的Handler实例,调用sendMessage(Message msg)方法。

四、实例

1、主线程接收数据,并将之发送至子线程中完成一些耗时操作

package com.ljh.handlerdemo1;import java.util.ArrayList;import java.util.List;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.app.Activity;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {	private final String UPPER_NUMBER = "upper";	private CalThread calThread;	@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentView(R.layout.activity_main);		calThread = new CalThread();		Thread t = new Thread(calThread);		t.start();	}	public void cal(View v) {		EditText et_digit = (EditText) findViewById(R.id.et_digit);		Message msg = new Message();		msg.what = 0x1233;		Bundle bundle = new Bundle();		bundle.putInt(UPPER_NUMBER,				Integer.parseInt(et_digit.getText().toString()));		msg.setData(bundle);		calThread.handler.sendMessage(msg);	}	class CalThread implements Runnable {		public Handler handler;		@Override		public void run() {			//1、调用 Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue			Looper.prepare();			handler = new Handler() {				// 2、有了Looper之后,创建Handler子类的实例,重写HandlerMessage()方法,该方法负责处理来自其它线程的消息。				@Override				public void handleMessage(Message msg)				{					if(msg.what == 0x1233)					{						int upper = msg.getData().getInt(UPPER_NUMBER);						List
nums = new ArrayList
(); // 计算从2开始、到upper的所有质数 outer: for (int i = 2 ; i <= upper ; i++) { // 用i处于从2开始、到i的平方根的所有数 for (int j = 2 ; j <= Math.sqrt(i) ; j++) { // 如果可以整除,表明这个数不是质数 if(i != 2 && i % j == 0) { continue outer; } } nums.add(i); } // 使用Toast显示统计出来的所有质数 Toast.makeText(MainActivity.this , nums.toString() , Toast.LENGTH_LONG).show(); } } }; //调用Looper的loop()方法启动Looper。 Looper.loop(); }}}

参考归档代码HandlerDemo1

2、在主线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可。

package org.crazyit.event;import java.util.Timer;import java.util.TimerTask;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.ImageView;/** * Description: * 
site: crazyit.org *
Copyright (C), 2001-2014, Yeeku.H.Lee *
This program is protected by copyright laws. *
Program Name: *
Date: * @author Yeeku.H.Lee kongyeeku@163.com * @version 1.0 */public class HandlerTest extends Activity{ // 定义周期性显示的图片的ID int[] imageIds = new int[] { R.drawable.java, R.drawable.ee, R.drawable.ajax, R.drawable.xml, R.drawable.classic }; int currentImageId = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final ImageView show = (ImageView) findViewById(R.id.show); final Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { // 如果该消息是本程序所发送的 if (msg.what == 0x1233) { // 动态地修改所显示的图片 show.setImageResource(imageIds[currentImageId++ % imageIds.length]); } } }; // 定义一个计时器,让该计时器周期性地执行指定任务 new Timer().schedule(new TimerTask() { @Override public void run() { // 发送空消息 myHandler.sendEmptyMessage(0x1233); } }, 0, 1200); }}

转载于:https://www.cnblogs.com/jediael/p/4304186.html

你可能感兴趣的文章
代理模式
查看>>
Confluence 6 系统运行信息中的 JVM 内存使用情况
查看>>
Confluence 6 升级以后
查看>>
用JS实现版面拖拽效果
查看>>
二丶CSS
查看>>
《avascript 高级程序设计(第三版)》 ---第二章 在HTML中使用Javascript
查看>>
JS一些概念知识及参考链接
查看>>
TCP/IP协议原理与应用笔记24:网际协议(IP)之 IP协议的简介
查看>>
SAP HANA开发中常见问题- 基于SAP HANA平台的多团队产品研发
查看>>
游戏中的心理学(一):认知失调有前提条件
查看>>
WHAT I READ FOR DEEP-LEARNING
查看>>
【Ruby】Ruby在Windows上的安装
查看>>
Objective C 总结(十一):KVC
查看>>
BZOJ 3747 洛谷 3582 [POI2015]Kinoman
查看>>
vue实战(7):完整开发登录页面(一)
查看>>
Visual Studio自定义模板(二)
查看>>
【Mood-20】滴滤咖啡做法 IT工程师加班必备 更健康的coffee 项目经理加班密鉴
查看>>
读《构建之法-软件工程》第四章有感
查看>>
使用 Printf via SWO/SWV 输出调试信息
查看>>
.net 分布式架构之分布式锁实现(转)
查看>>