深入了解Handler的消息传递机制

出于性能优化的考虑,android的UI操作并不是安全的,如果有多个线程并发操作UI组件,则可能导致线程安全问题.为了解决这个问题,Android制定了一个规则,只允许UI线程来修改Activity中的UI组件.

UI线程(主线程 Main Thread):当程序第一次启动时,android会同时启动一条主线程(Main Thread),主线程主要负责处理与UI相关的事件,比如说用户的按键事件,用户接触屏幕的事件及屏幕绘图事件,并把相应的事件分发到对应的组件进行处理.即主线程就是UI线程.

Android的消息传递机制主要是为了解决Android应用的多线程问题------Android只允许UI线程修改Activity里的UI组件,这就导致了一个问题:如果新启动一个线程便无法动态改变界面组件的属性值.但是在实际的Android应用开发中,尤其是涉及到动画的游戏开发中,需要让新启动的线程周期性的改变界面组件的属性值,这便需要Handler的消息传递机制来实现了

Handler类的主要作用

Handler类的主要作用有两个:

1.在新启动的线程中发送消息

2.在主线程中获取,处理消息.

牵扯到两个问题:新启动的线程何时发送消息?主线程何时去获取消息?

为了让主线程"适时"地处理新启动线程发送的消息,只能通过回调的方式实现.需要我们重写Handler类中处理消息的方法,

当启动的新线程发送消息时,消息会发送到与这个新线程关联的MessageQueue,而Handler会不断地从MessageQueue中获取并处理消息-------这将导致Handler类中处理消息的方法被回调.

深入了解Handler的消息传递机制_第1张图片
1

天哥在视频中说了一个经常用的方法是handler.postDelayed(Runnable ,delayMiuis);

深入了解Handler的消息传递机制_第2张图片
2

我们可以这么认为,在onCreate方法中的进程为主进程,因为onCreat方法多与UI相关事务有关.而Android只允许在主进程中访问/修改Activity界面组件.而在主线程中可以直接创建Handler对象,因为系统会自动帮我们创建好Looper对象,而Looper对象会自动帮我们配置好相关的MessageQueue对象,然后就是重写Handler的handleMessage方法(注意:因为主线程中没有显示创建Looper对象,系统自动创建的Looper对象所以最后不用显示启动Looper的loop()方法,或者我们可以认为是系统自动启动了Looper的loop()方法)(若是新建线程则最后不要忘了启动Looper的loop()方法来启动Looper.)

Handler相关的三大组件

与Handler一起工作的组件有:

Message:Handler接收和处理的对象

Looper:每个线程只能拥有一个Looper.它的loop方法负责读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理

MessageQueue:消息队列,采用先进先出的方式来管理Message.程序在创建Looper对象的时候,会在Looper的构造器中创建MessageQueue对象.Looper的构造器源码如下:

在我们平时要多看一些源码提高我们的理解水平

深入了解Handler的消息传递机制_第3张图片
3

总结

Handler的作用发送消息和接收消息.

如果程序使用Handler发送消息,由Handler发送消息必须被指定到指定的MessageQueue.如果希望Handler正常工作,必须在当前进程中有一个MessageQueue;否则消息Message就没有MessageQueue进行保存了.不过经过我们上面的分析:MessageQueue是由Looper管理的,在创建Looper对象的时候,会在Looper的构造器中创建MessageQueue对象,也就是说如果希望Handler正常工作,则必须在当前进程中有一个Looper对象,为了保证当前进程中有个Looper对象可以分下列情况处理:

深入了解Handler的消息传递机制_第4张图片
4

prepare方法保证每个线程最多只能有一个Looper对象,然后调用Looper的静态loop()方法来启动它.loop()方法使用一个死循环不断去除MessageQueue中的消息,并将取出的消息分给该消息对应的Handler进行处理.

深入了解Handler的消息传递机制_第5张图片
5

ANR异常:只要在主线程(UI线程)中执行需要消耗大量时间的操作,都会引发ANR,因为这样会导致Android应用程序无法响应输入事件和Broadcast.

深入了解Handler的消息传递机制_第6张图片
6

在新建线程中创建Handler必须要创建Looper对象!!

深入了解Handler的消息传递机制_第7张图片
7

package org.crazyit.handler;

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 MainActivityextends AppCompatActivity {

static final StringUPPER_NUM ="upper";

    EditTextetNum;

    CalThreadcalThread;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        etNum = 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);

    }

//定义一个线程类

    class CalThreadextends Thread

{

public HandlermHandler;

        public void run()

{

Looper.prepare();

            mHandler =new Handler()

{

// 定义处理消息的方法

                @Override

                public void handleMessage(Message msg)

{

if(msg.what ==0x123)

{

int upper = msg.getData().getInt(UPPER_NUM);

                        List nums =new ArrayList<>();

                        // 计算从2开始、到upper的所有质数

                        outer:

for (int i =2 ; i <= upper; i++)

{

// 用i除以从2开始、到i的平方根的所有数

                            for (int j =2 ; j <= Math.sqrt(i); j++)

{

// 如果可以整除,则表明这个数不是质数

                                if(i !=2 && i % j ==0)

{

continue outer;

                                }

}

nums.add(i);

                        }

// 使用Toast显示统计出来的所有质数

                        Toast.makeText(MainActivity.this, nums.toString()

, Toast.LENGTH_LONG).show();

                    }

}

};

            Looper.loop();

        }

}

}

布局文件xml代码如下


深入了解Handler的消息传递机制_第8张图片

你可能感兴趣的:(深入了解Handler的消息传递机制)