美文网首页
深入了解Handler的消息传递机制

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

作者: 小徐andorid | 来源:发表于2018-03-25 20:37 被阅读0次

    出于性能优化的考虑,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类中处理消息的方法被回调.

    1

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

    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的构造器源码如下:

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

    3

    总结

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

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

    4

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

    5

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

    6

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

    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的消息传递机制

          本文链接:https://www.haomeiwen.com/subject/dcfkcftx.html