一、背景

出于性能优化考虑,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<Integer> nums = new ArrayList<Integer>();
// 计算从2开始、到upper的所有质数
outer:
for (int i = ; i <= upper ; i++)
{
// 用i处于从2开始、到i的平方根的所有数
for (int j = ; j <= Math.sqrt(i) ; j++)
{
// 如果可以整除,表明这个数不是质数
if(i != && i % j == )
{
continue outer;
}
}
nums.add(i);
}
// 使用Toast显示统计出来的所有质数
Toast.makeText(MainActivity.this , nums.toString()
, Toast.LENGTH_LONG).show();
}
} };
//调用Looper的loop()方法启动Looper。
Looper.loop();
}
}
}

xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" > <EditText
android:id="@+id/et_digit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/limit" /> <Button
android:id="@+id/bt_prime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cal"
android:onClick="cal"
android:layout_below="@id/et_digit" /> </RelativeLayout>

参考归档代码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:
* <br/>site: <a href="http://www.crazyit.org">crazyit.org</a>
* <br/>Copyright (C), 2001-2014, Yeeku.H.Lee
* <br/>This program is protected by copyright laws.
* <br/>Program Name:
* <br/>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 = ; @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);
}
}, , );
}
}

Android Handler消息传递的更多相关文章

  1. Android Handler消息传递机制

    在Android系统中,类Handler主要有如下两个作用. 在新启动的线程中发送消息. 在主线程中获取.处理消息. 类Handler在实现上述作用时,首先在新启动的线程中发送消息,然后在主线程中获取 ...

  2. Android学习笔记-事件处理之Handler消息传递机制

    内容摘要:Android Handler消息传递机制的学习总结.问题记录 Handler消息传递机制的目的: 1.实现线程间通信(如:Android平台只允许主线程(UI线程)修改Activity里的 ...

  3. Android异步消息传递机制源码分析

    1.Android异步消息传递机制有以下两个方式:(异步消息传递来解决线程通信问题) handler 和 AsyncTask 2.handler官方解释的用途: 1).定时任务:通过handler.p ...

  4. 安卓开发_深入理解Handler消息传递机制

    一.概述 因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面 二.消息类(Message) 消息类是存 ...

  5. Android Handler leak 分析及解决办法

    In Android, Handler classes should be static or leaks might occur, Messages enqueued on the applicat ...

  6. Android Handler练习

    package com.example.myact12; import java.util.Random; import android.support.v7.app.ActionBarActivit ...

  7. Android Handler简单使用

    package com.example.myhandlertest3; import android.os.Bundle; import android.os.Handler; import andr ...

  8. Android Handler的使用

    大家好我们这一节讲的是Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title. 首先我们看一下习惯了Java编程的人,在不知道Handl ...

  9. [Android]Handler的消息机制

    最经面试中,技术面试中有一个是Handler的消息机制,细细想想,我经常用到的Handler无非是在主线程(或者说Activity)新建一个Handler对象,另外一个Thread是异步加载数据,同时 ...

随机推荐

  1. C# 生成简单验证码

    网站登录总是会用到验证码,生成验证码对于C#来说很简单.因为有专门封装好的GDI+类可以直接调用使用具体代码如下 using System; using System.Collections.Gene ...

  2. Redis集群明细文档

    Redis目前版本是没有提供集群功能的,如果要实现多台Redis同时提供服务只能通过客户端自身去实现(Memchached也是客户端实现分布式).目前根据文档已经看到Redis正在开发集群功能,其中一 ...

  3. WPF-控件-ListView

    <Window x:Class="DataTemplate2.MainWindow" xmlns="http://schemas.microsoft.com/win ...

  4. 11、创建不使用XAML的WPF应用程序

    首先新建一个空的项目,然后添加一个类,引用一下程序集: PresentationCore.dll PresentationFramework.dll WindowsBase.dll namespace ...

  5. Entity Framework学习笔记(五)----Linq查询(2)---贪婪加载

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,我们使用了Linq对Entity Framework进行了一个查询,但是通过学习我们却发现了懒加载给我来的性能上的 ...

  6. ios状态栏调整 简单动画的知识点

    首先状态栏式view的属性,所以在viewController中直接重写: /** 修改状态栏 */ - (UIStatusBarStyle)preferredStatusBarStyle { // ...

  7. MITK Tutorial (三)

    Step 2: Use the template with the plugins to read a image 在exampleplugin插件中QmitkAwesomeView.cpp中添加头文 ...

  8. MVC的Ajax的异步请求

    MVC的Ajax的异步请求 在这里小写一下MVC的异步请求的一点小总结. 个人认为是有两种的,一种就是跟webform一样的,依旧是使用jQuery的$.get()方法,只是请求地址不同,webfor ...

  9. android 播放语音文件出现 prepare failed ,不能下载amr文件

    amr文件的路径正确,但是android 却不能播放出来. 调试发现时根本就没有下载下来 原因: IIS服务器不允许下载该文件,需要配置MIME 解决方法: 进入IIS目录,配置MIME

  10. javascript_22_for_js控制div每五个换一行

    2. 3. css: <style type="text/css"> div{height: 50px; width: 50px; background: #f1161 ...