1.Android制定了一条简单的原则:只允许UI线程(亦即主线程)修改Activity中的UI组件。当一个程序第一次启动时,Android会同时启动一条主线程,主线程主要负责处理与UI相关的事件,如用户的按键事件、用户接触屏幕的事件、屏幕绘图事件,并把相关的事件分发到相应的组件进行处理,所以主线程通常又叫做UI线程。


Handler存在的意义就是一个消息机制, 可以在一个线程中创建并在另一个线程中触发


2.Handler的作用:

  • (1)在一个线程中发送消息。
  • (2)在另一个线程中获取、处理消息。

3.Handler类包含如下方法用于发送、处理消息(这里只列出了常用的部分,还有更多可以自己去找):

  • ♦ void handlerMessage(Message msg):处理消息的方法,该方法通常用于被重写。
  • ♦ final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息。
  • ♦ sendEmptyMessage(int what):发送空消息
  • ♦ final boolean sendMessage(Message msg):立即发送消息,注意这块返回值,如果message成功的被放到message queue里面则返回true,反之,返回false;

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

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

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

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

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

在调用线程中完成:

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

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

5.下面这个例子是Handler在主线程中获取,处理消息,在子线程中发送消息,这个例子handler写在主线程中。

main.xml

<?xml version="1.0" encoding="utf-8"?>
<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="com.dragon.testfuction.Main"><ImageView
        android:id="@+id/show"android:layout_width="wrap_content"android:layout_height="wrap_content" />
</RelativeLayout>

main.java

package com.dragon.testfuction;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;public class Main extends AppCompatActivity  {//    定义图片显示IDint[] imageIds = new int[]{R.drawable.one,R.drawable.two,R.drawable.three,R.drawable.four};int currentImageId = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);final ImageView show = (ImageView) findViewById(R.id.show);final Handler myHandler = new Handler(){@Overridepublic void  handleMessage(Message msg){
//                检查消息发送来源,如果是本程序发送的if(msg.what == 0x1233){
//                    动态修改图片show.setImageResource(imageIds[currentImageId++%imageIds.length]);}}};
//定义一个定时器,周期性的执行指定任务new Timer().schedule(new TimerTask(){@Overridepublic void run(){//在子线程中拿到父线程中创建的handle对象,通过该对象来向父线程的消息队列发送消息(通过这种方式,可以在其它子线程中与主线程通信来由UI线程更新界面)myHandler.sendEmptyMessage(0x1233);}},0,1200);
}
}

6。为避免ANR,应该在子线程中执行耗时较长的操作,而此操作完成后,有可能需要通知主线程修改UI。在子线程中执行耗时任务后,通知主线程修改UI组件的例子:使用新进程计算质数,并用Toast显示这个例子是在主线程中发送消息,在子线程中获取,处理消息(例子来自疯狂java讲义),这个例子handle写在子线程中。

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"tools:context="com.dragon.testfuction.Main"><EditText
        android:id="@+id/etNum"android:inputType="number"android:layout_width="wrap_content"android:layout_height="wrap_content"android:hint="please input upper number"/><Button
        android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="cal"android:text="calculate"/>
</LinearLayout>

main.java

package com.dragon.testfuction;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;public class Main extends AppCompatActivity  {static final String UPPER_NUM = "upper";EditText etNum;CalThread calThread;
//    定义一个线程类class CalThread extends Thread {public Handler mHandler;public void run(){
//                创建looper对象,每一个线程使用Handle都要有一个looper对象Looper.prepare();
//                子线程中定义handler获取处理消息mHandler = new Handler(){
//                    定义处理信息的方法@Overridepublic void handleMessage(Message msg){if(msg.what == 0x123){int upper = msg.getData().getInt(UPPER_NUM);List<Integer> nums = new ArrayList<Integer>();outer:
//                                质数也是素数,除了1和它本身外,不能被其它整除for(int i =2;i <=upper;i++){for(int j=2; j<= Math.sqrt(i);j++){
//                                        如果可以整除,说明不是质数if(i!=2 && i%j==0){continue outer;}}nums.add(i);}
//                                用Toast显示所有统计出来的质数Toast.makeText(Main.this,nums.toString(),Toast.LENGTH_LONG).show();}}};Looper.loop();//启动looper}}@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);etNum = (EditText) findViewById(R.id.etNum);calThread = new CalThread();calThread.start();//启动新线程}
//按钮事件点击处理函数public void cal(View source){
//        创建消息Message msg = new Message();msg.what = 0x123;Bundle bundle = new Bundle();bundle.putInt(UPPER_NUM,Integer.parseInt(etNum.getText().toString()));msg.setData(bundle);
//        在主线程中想新线程中的Handler发送消息calThread.mHandler.sendMessage(msg);//在主线程中发送消息}
}

7.总结:

8.注意

  • UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;
  • Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象
  • Message:Handler接收与处理的消息对象
  • MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
  • Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!

looper.prepare提供源码如下:

  /** Initialize the current thread as a looper.* This gives you a chance to create handlers that then reference* this looper, before actually starting the loop. Be sure to call* {@link #loop()} after calling this method, and end it by calling* {@link #quit()}.*/public static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}

9.根据上面两个例子,大家注意区分写在主线程中和子线程中的区别,如有问题欢迎大家留言,另有从事AR原生开发的可以加入下面的群或是关注微信公众号AR引路人

Reference:

1.http://www.runoob.com/w3cnote/android-tutorial-handler-message.html
2.http://www.nljb.net/default/Android%E4%B9%8BHandler%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92%E6%9C%BA%E5%88%B6%E4%BD%BF%E7%94%A8/
3.http://www.itmmd.com/201502/575.html
4.http://www.kancloud.cn/digest/tttkkk/125281

android studio for android learning (十九 ) 最新Handler消息传递机制全解相关推荐

  1. android handler 传递对象,Android之Handler消息传递机制详解

    前言 在Android开发中,多线程应用是非常频繁的,其中Handler机制随处可见. 下面就本人对Handle的一些理解与大家一起分享,共同回顾下Handle异步消息传递机制. 1.Handler是 ...

  2. Android开发笔记(八十九)单例模式

    基本概念 单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,从而方便对实例个数的控制并节约系统资源. 单例模式有三个特点: 1.某个类只能有一个实例: 2.它要自行创建这个实例: 3.它只有 ...

  3. Android开发笔记(七十九)资源与权限校验

    硬件资源 因为移动设备的硬件配置各不相同,为了防止使用了不存在的设备资源,所以要对设备的硬件情况进行检查.一般情况下,前置摄像头.部分传感器在低端手机上是没有的,像SD卡也可能因为用户没插卡使得找不到 ...

  4. 【Android Studio】Android Studio 搭建开发环境(Linux Ubuntu篇)

    Windows篇:[Android Studio]Android Studio 搭建开发环境(Windows篇)_dandelionela的博客-CSDN博客 Ubuntu篇参考: Ubuntu 18 ...

  5. 【Android应用开发】Android Studio 简介 (Android Studio Overview)

    一. Intelij IDEA 环境简介 Android Studio 来源 : Android Studio 是 Intelij IDEA 的免费版本 + Android SDK 集成的; -- I ...

  6. AndroidStudio中打开新项目提示:Unrecognized Android Studio (or Android Support plugin for IntelliJ IDEA)

    在导入Google官方项目时提示我们Unrecognized Android Studio (or Android Support plugin for IntelliJ IDEA) version ...

  7. 使用Android Studio搭建Android集成开发环境

    一.Android Studio简单介绍 2013年GoogleI/O大会首次发布了Android Studio IDE(Android平台集成开发环境).它基于Intellij IDEA开发环境,旨 ...

  8. android+图标+i_explore+无背景,Android Studio中Android Device Monitor中的File Explore不显示文...

    环境:操作系统是Mac,模拟器 问题:Android Studio中Android Device Monitor中的File Explore不显示文件 本人在自学文件存储,想查看"dada/ ...

  9. Android开发工具Android Studio、Android SDK和Genymotion完全配置

    所谓"工欲善其事,必先利其器".Android Studio 是谷歌推出一个Android集成开发工具,基于IntelliJ IDEA. 类似 Eclipse ADT,Androi ...

  10. 在Android Studio中将Android工程变为Library使用

    在Android Studio中将Android工程变为Library使用 转载2016-03-28 10:43:58 有时候网上会有些工程格式不是我们想要的Library格式可以直接给AS使用.这时 ...

最新文章

  1. Pytorch view()、squeeze()、unsqueeze()、torch.max()
  2. 【计算机网络(微课版)】第5章 传输层 课后习题及答案
  3. 疫情撬动游戏产业“底层认知”,正向价值愈发突显
  4. VS Code非英语版本连接TFS错误解决方案
  5. 2019年嵌入式开发系统详细分析告诉你是否还值得去学习
  6. EC+VO+SCOPE for ES3
  7. 手动安装Linux网卡驱动程序
  8. 联合主键违反唯一性约束_(变强、变秃)Java从零学习024/252数据库之定义约束。...
  9. vue router-view 匹配路由后,第一次可以点击,再次点击同一个路由无响应,如何处理?
  10. 地面控制点的定义与作用_彩色透水混凝土路面在海绵城市建设中能起多大作用?...
  11. 阿里云linux服务器到期后续费,网站打不开解决方法之一
  12. 【python之路11】集合数据类型(set)
  13. cc2640蓝牙数据接收丢包问题
  14. 永久免费的内网端口映射工具推荐【无公网IP】
  15. TASKCTL-函数表达式分类
  16. 新能源汽车控制技术分享:VCU整车控制器电控开发
  17. 裁剪用C语言,多边形裁剪
  18. 挂载NTFS分区导致Docker容器无法启动,Exited (137)错误
  19. CTex listings宏包出错undefined control sequence,换成verbatim解决问题
  20. 404, NOT_FOUND - no queue 'rep_queue' in vhost '/'

热门文章

  1. 【中级篇】Linux下搭建MySQL数据库系统
  2. 关于在用Swift开发iOS时如何隐藏NavigationBar和TabBar
  3. Android学习小Demo(19)利用Loader来实时接收短信
  4. 数据结构利器之私房STL(中)
  5. POJ 2391 Ombrophobic Bovines【二分+最大流】
  6. Oracle PL/SQL中使用%TYPE和%ROWTYPE的方法
  7. Hibernate 主键
  8. wordpress让百度分享支持https
  9. phonegap文件上传(java_php),Android应用开发之使用PhoneGap实现位置上报功能
  10. qt中如何使用mysql_qt中如何使用mysql 以及静态编译qt中如何加上mysql(1)