Android的Handler Looper Message机制应用实例与详解(一)

Android的UI操作不是线程安全的(出于提高性能考虑,避免实现多线程同步等机制所引入的延时),若多个线程同时对UI元素进行操作,可能导致线程安全问题。因此,Android中做了严格的规定:只有UI主线程才能对UI进行设置与操作。

在实际编程中,为了避免UI界面长时间得不到响应而导致的ANR(Application Not Responding)异常,通常将网络访问、复杂运算等一些耗时的操作被放在子线程中执行。这就需要子线程在运行完毕后将结果返回到主线程并通过UI进行显示。在Android中,是通过Handler+Loop+MessageQueue实现线程间通信的。

先看两个实例:

实例1:模拟通过网络下载数据并返回UI显示。

操作过程为:1.UI线程获得用户请求。2.启动子线程完成网络数据下载(网络下载过程通过强制子线程休眠若干秒来模拟)。3.子线程将下载的数据返回UI线程并显示。

主要代码如下:

public class MainActivity extends ActionBarActivity {

	private Button mButton;
	private TextView mTextView;
	private Handler mHandler;
	private Thread mNetAccessThread;
	private ProgressDialog mProgressDialog;
	private int mDownloadCount = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fragment_main);

		mButton = (Button) findViewById(R.id.btReqNet);
		mTextView = (TextView) findViewById(R.id.tvDownload);

		//设置按钮的点击事件监听器
		mButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				showProgressDialog("","正在下载...");
				//启动子线程进行网络访问模拟
				mNetAccessThread = new ChildTread();
				mNetAccessThread.start();
			}
		});

		//继承Handler类并覆盖其handleMessage方法
		mHandler = new Handler(){
			//覆盖Handler类的handleMessage方法
			//接收子线程传递的数据并在UI显示
			@Override
			public void handleMessage(Message msg) {
				switch (msg.what) {
				case 1:
					mTextView.setText((String) msg.obj);
					dismissProgressDialog();
					break;
				//可以添加其他情况,如网络传输错误
				//case...
				default:
					break;
				}
			}
		};

	}

	class ChildTread extends Thread {
		@Override
		public void run() {
			//休眠6秒,模拟网络访问延迟
			try {
				Thread.sleep(6000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//将结果通过消息返回主线程
			Message msg = new Message();
			msg.what = 1;
			mDownloadCount ++;
			msg.obj = new String("第"+mDownloadCount+"次从网上下载的数据");
			mHandler.sendMessage(msg);
		}
	};

	/**
        * 开启progressDialog.
        *
        * @param title 对话框标题.
        * @param content 对话框正文.
        */
	protected void showProgressDialog(String title,String content) {
		mProgressDialog = new ProgressDialog(this);
		if(title != null)
			mProgressDialog.setTitle(title);
		if(content != null)
			mProgressDialog.setMessage(content);
		mProgressDialog.show();
	}

	/**
        * 关闭progressDialog.
        *
        */
	protected void dismissProgressDialog() {
		if(mProgressDialog != null)
		{
			mProgressDialog.dismiss();
		}

	}

}

程序运行效果:

点击下载按钮,UI线程通过handler.sendMessage()向子线程发送消息,子线程收到消息后启动数据下载(通过休眠线程模拟)。

下载完毕,子线程将下载数据返回主线程并显示。

    实例2:模拟子线程向主线程发送消息。

操作过程为:1.UI线程获得用户输入的消息内容。2.通过Handler将消息发送给子线程。3.子线程获得消息并通过Toast将内容打印。

主要代码如下:

public class MainActivity extends ActionBarActivity {

	private EditText mEditText;
	private Button mButton;
	private Handler mHandler;
	private Thread mChildTread;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fragment_main);

		mEditText = (EditText) findViewById(R.id.etEditText);
		mButton = (Button) findViewById(R.id.btButton);

		// 设置按钮的点击事件监听器
		mButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Message msg = new Message();
				msg.what = 1;
				msg.obj = mEditText.getText();
				//将消息发送到子线程
				mHandler.sendMessage(msg);
				mEditText.setText("");

			}
		});

		//启动子线程进行msg接收
		mChildTread = new ChildTread();
		mChildTread.start();
	}

	/**
	* 子线程为内部类,可以直接访问其外部类的mHandler变量
	*
	*/
	class ChildTread extends Thread {
	    @Override
	    public void run() {
	        //以下三步是handler looper机制工作的固定模式
		Looper.prepare();

		mHandler = new Handler() {
		    public void handleMessage(Message msg) {
		        // process incoming messages here
			switch (msg.what) {
			case 1:
			    //子线程无权操作UI,只能通过Toast.makeText将收到的消息显示
			    String st = msg.obj.toString();
			    if (st == null || st.equals(""))  
			        st = "收到的消息内容为空";
			    else
			        st = "收到来自主线程的消息:" + st;
			    Toast.makeText(MainActivity.this, st, 6000).show();
			 break;
			//可以添加其他情况,如传输错误
			//case...
			default:
			break;
			}
		    }
		};
		Looper.loop();
	    }
	};
}

程序运行效果:

小结:Android通过Handler+Looper+MessageQueue机制实现线程间的通信,本文通过两个简单的实例分别基于该机制实现了UI线程到子线程和子线程到UI线程的消息传递。下一篇博文将会对Handler Looper机制的原理进行深入研究。

时间: 2025-01-01 09:55:55

Android的Handler Looper Message机制应用实例与详解(一)的相关文章

Android的Handler Looper Message机制应用实例与详解(二)

上一篇博文给出了Android中基于Handler Looper机制实现线程间通信的两个典型实例.本文将对该机制的基本原理进行较深入的研究.个人认为,学好Android编程最好的老师就是Android的源代码,下面将基于Android-19的源码进行分析,重点阐述分析思路. 要分析Handler Looper机制,自然想到去看Handler类和Looper类的源码(分别位于Handler.java和Looper.java两个文件中).简单阅读两个类的描述后,在Looper类的描述中能找到以下一段

Android异步消息处理 Handler Looper Message关系源码分析

# 标签: 读博客 对于Handler Looper Message 之前一直只是知道理论,知其然不知所以然,看了hongyang大神的源码分析,写个总结帖. 一.概念.. Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念. 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handle

Android研究之手势交互实例实现详解

 先来几张效果图: 一.没有抛掷: 二.向右抛掷一次 三.向右再抛掷一次 接下来说说Android开发中对于手势动作的识别参考资料... 首先,在Android系统中,每一次手势交互都会依照以下顺序执行. 1. 接触接触屏一刹那,触发一个MotionEvent事件. 2. 该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象. 3. 通过GestureDetector(手势识别器)转发次MotionEvent对象至OnGestureList

Android M新特性Doze and App Standby模式详解

参考: Optimizing for Doze and App Standby Android M新特性Doze and App Standby模式详解 深入android6.0 设备 idle状态 Android M 的 Doze 模式下第三方推送服务还能用吗? 一.Optimizing for Doze and App Standby 从Android6.0开始,Android提供了两种省电延长电池寿命的功能:Doze和App Standby: 表现形式:当设备没有连接到电源,设备进入Doz

(转)Java经典设计模式(3):十一种行为型模式(附实例和详解)

原文出处: 小宝鸽 Java经典设计模式共有21中,分为三大类:创建型模式(5种).结构型模式(7种)和行为型模式(11种). 本文主要讲行为型模式,创建型模式和结构型模式可以看博主的另外两篇文章:Java经典设计模式之五大创建型模式(附实例和详解).Java经典设计模式之七大结构型模式(附实例和详解). 行为型模式细分为如下11种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 接下来对11种行为型模式逐个进行介

Android开发之AudioManager(音频管理器)详解

AudioManager简介: AudioManager类提供了访问音量和振铃器mode控制.使用Context.getSystemService(Context.AUDIO_SERVICE)来得到这个类的一个实例. 公有方法: Public Methods int abandonAudioFocus(AudioManager.OnAudioFocusChangeListenerl) 放弃音频的焦点. void adjustStreamVolume(int streamType, int dir

Java设计模式之十一种行为型模式(附实例和详解)

Java经典设计模式共有21中,分为三大类:创建型模式(5种).结构型模式(7种)和行为型模式(11种). 本文主要讲行为型模式,创建型模式和结构型模式可以看博主的另外两篇文章:J设计模式之五大创建型模式(附实例和详解). 设计模式之七大结构型模式(附实例和详解). 行为型模式细分为如下11种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 接下来对11种行为型模式逐个进行介绍. 一.策略模式 策略模式定义了一系列

SpringBoot启动机制(starter机制)核心原理详解

作者:MyBug 一.前言 使用过springboot的同学应该已经知道,springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程.本文的目的就是一步步分析springboot的启动过程,这次主要是分析springboot特性自动装配.那么首先带领大家回顾一下以往我们的web项目是如何搭建的,通常我们要搭建一个基于Spring的Web应用,我们需要做以下一些工作:pom文件中引入相关jar包,包括spring.springmvc.redis.mybaits.l

Android基础入门教程——8.3.16 Canvas API详解(Part 1)

Android基础入门教程--8.3.16 Canvas API详解(Part 1) 标签(空格分隔): Android基础入门教程 本节引言: 前面我们花了13小节详细地讲解了Android中Paint类大部分常用的API,本节开始我们来讲解 Canvas(画板)的一些常用API,我们在Android基础入门教程--8.3.1 三个绘图工具类详解 中已经列出了我们可供调用的一些方法,我们分下类: drawXxx方法族:以一定的坐标值在当前画图区域画图,另外图层会叠加, 即后面绘画的图层会覆盖前