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

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.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

时间: 2024-08-02 03:18:10

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

Android异步更新UI的方式之使用Handler消息传递机制

由于性能要求,android要求只能在UI线程中更新UI,要想在其他线程中更新UI,给大家介绍一种方式:使用Handler消息传递机制. 下面用这种方式更新一个TextView: package com.example.runonuithreadtest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.widget.TextView; public

Android Handler消息传递机制详解

1.为什么要用Handler 出于性能优化的考虑,Android UI操作并不是线程安全,如果有多个线程并发操作UI组件,可能导致线程安全问题.可以设想下,如果在一个Activity中有多个线程去更新UI,并且都没有加锁机制,可能会导致什么问题? 界面混乱,如果加锁的话可以避免该问题但又会导致性能下降.因此,Android规定只允许UI线程修改Activity的UI组件.当程序第一次启动时,Android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,比如用户

Android项目实战(二十九):酒店预定日期选择

原文:Android项目实战(二十九):酒店预定日期选择 先看需求效果图:              几个需求点: 1.显示当月以及下个月的日历 (可自行拓展更多月份) 2.首次点击选择"开始日期",再次点击选择"结束日期" (1).如果"开始日期" "结束日期" 相同  (2).如果"开始日期" "结束日期" 不同,且"结束日期" 晚于 "开始日期&quo

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

一. Intelij IDEA 环境简介 Android Studio 来源 : Android Studio 是 Intelij IDEA 的免费版本 + Android SDK 集成的; -- Intelij 文档参考 : https://www.jetbrains.com/idea/help/intellij-idea.html ; 1. Intelij 与 Eclipse 区别 (1) Intelij 与 Eclipse 对应关系 Android Studio 与 Eclipse 对应

Android开发新手学习总结(一)——使用Android Studio搭建Android集成开发环境

[新手连载]一:使用Android Studio搭建Android集成开发环境http://bbs.itcast.cn/forum.php?mod=viewthread&tid=87055&fromuid=150705 (出处: 传智播客论坛_传智播客旗下社区) 一.Android Studio简单介绍 2013年GoogleI/O大会首次发布了Android Studio IDE(Android平台集成开发环境).它基于Intellij IDEA开发环境,旨在取代Eclipse和ADT(

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

一.Android Studio简单介绍 2013年GoogleI/O大会首次发布了Android Studio IDE(Android平台集成开发环境).它基于Intellij IDEA开发环境,旨在取代Eclipse和ADT(Android开发者工具)为开发者提供更好的开发工具.既然Google一直在努力推广,相信不久以后就有望赶上Eclipse. 相比Eclipse,Android Studio IDE有自己的特点: 对UI界面设计和编写代码有更好地支持,可以方便地调整设备上的多种分辨率.

Android 基础总结:( 十四)Handler详解(上)

Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发,比如说,你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作. 如果此时需要一个耗时的操作,例如:联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,会收

Android开发学习总结(二)——使用Android Studio搭建Android集成开发环境

有很长一段时间没有更新博客了,最近实在是太忙了,没有时间去总结,现在终于可以有时间去总结一些Android上面的东西了,很久以前写过这篇关于使用Android Studio搭建Android集成开发环境,不过一直没有发表出来,写这篇文章的目的是记录一下Android开发环境的搭建过程,这篇文章写得一般般,主要是记录了整个搭建过程,没什么技术含量,觉得有帮助的朋友就看一下! 一.Android Studio简单介绍 2013年GoogleI/O大会首次发布了Android Studio IDE(A

使用Android Studio开发android应用(持续更新)

使用Android Studio开发android应用 --------------------转载请注明出处:coder-pig 前言: 在2013年5月16日开发者大会上,google公司发布了一个新的集成开发环境:Android Studio 该IDE是专门用来开发安卓应用程序的,如果你需要使用Java的话就需要下载Java的IDE了! google慢慢地已经把重心放到Android Studio上了,所以有必要熟悉下这个IDE开发环境! 本篇博文会不定期地进行更新!对遇到的问题以及一些新