android studio for android learning (十九 ) 最新Handler消息传递机制全解
2016-07-17 20:51
495 查看
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 { // 定义图片显示ID int[] imageIds = new int[]{ R.drawable.one, R.drawable.two, R.drawable.three, R.drawable.four }; int currentImageId = 0; @Override protected 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(){ //在子线程中拿到父线程中创建的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(){ // 定义处理信息的方法 @Override public 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 } } @Override public 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.html2.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创建一个最简单的跳转activity
- Android-对相册中的图片进行上传或下载
- 如何阻止Android的反编译apk
- Android-自定义手势识别-复杂手势识别
- android 快捷键
- Android—强制下线功能的实现
- Android的反编译
- android 五大布局-线性布局(LinearLayout)
- Android基础——Activity之间传递参数
- 献给迷茫的大家
- Android 简单的适配问题
- 手势和触摸事件
- Android极光、小米、百度、jpush等一些推送简介
- Android 图案解锁 9宫格密码解锁
- Android中的回调函数
- ListView Item 中控件获得焦点 android:descendantFocusability用法简析
- Android学习笔记002-Bundle和intent-2016.7.17
- Android布局:gravity与layout_gravity的区别
- Android布局:gravity与layout_gravity的区别
- Android 免费短信验证码--Mob.com