浅谈Handler

简介: 前言积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得;Handler消息传递机制出于性能优化考虑,Android的UI操作并不是线程安全的,这意义着如果有多个线程并发操作UI组件,则可能导致线程安全问题。

前言

积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得;

Handler消息传递机制

出于性能优化考虑,Android的UI操作并不是线程安全的,这意义着如果有多个线程并发操作UI组件,则可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity里的UI组件。在实际开发中,需要让新启动的线程周期性地改变界面组件的属性值,这就需要借助于Handler的消息传递机制来实现了。

Handler类简介

Handler类的主要作用有两个。
  • 在新启动的线程中发送消息。
  • 在主线程中获取、处理消息。
Handler类的功能看似简单,似乎只要在新启动的线程中发送消息,在主线程中获取、处理消息。但这个过程涉及两个问题:新启动的线程何时发送消息呢?主线程何时去获取并处理消息呢?
为了让主线程能在适当的时机处理新启动的线程所发送的消息,显然只能通过回调的方式来实现——需要重写Handler类中处理消息的方法。
Handler类包含如下方法用于发送、处理消息。
  • void handleMessage(Message msg):处理消息的方法。通常被重写。
  • final boolean hasMessages(int what):检查消息队列是否包含what属性为指定值的消息。
  • final boolean hasMessages(int what, Object object):检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息。
  • sendEmptyMessage(int what):发送空消息。
  • final boolean sendEmptyMessageDelayed(int what,long delayMillis):指定多少秒后发送空消息。
  • final boolean sendMessage(Message msg):立即发送消息。
  • final boolean sendMessageDelayed(Message msg,long delayMillis)
本实例将通过一个新线程来周期性地修改ImageView所显示的图片,自动播放图片还可以使用ViewFlipper和AdapterViewFlipper组件来实现。

代码示例

MainActivity.java
public class MainActivity extends Activity {

    // 定义周期性显示的图片ID
    int[] imageIds = new int[]
    {
        R.drawable.baxianhua,
        R.drawable.dengta,
        R.drawable.juhua,
        R.drawable.kaola,
        R.drawable.qie,
        R.drawable.shamo,
        R.drawable.shuimo,
        R.drawable.yujinx
    };

    int currentImageId = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler);
        final ImageView show = (ImageView) findViewById(R.id.image);
        final Handler myHandler = new Handler()
        {

            @Override
            public void handleMessage(Message msg) {
                if(msg.what == 0x123)
                {
                    //动态地修改所显示的图片
                    show.setImageResource(imageIds[currentImageId++ % imageIds.length]);
                }
            }

        };

        //定义一个计时器,让该计时器周期性地执行指定任务
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {

                //发送空消息
                myHandler.sendEmptyMessage(0x123);
            }
        }, 0, 1200);//1.2秒更改一次
    }
}

效果

img_636daa29fe3d2ebe3dedba774b16b9cc.png
Screenshot_20171026-112831.png

Handler、Loop、MessageQueue的工作原理

为了更好地理解Handler的工作原理,下面介绍一下与Handler一起工作的几个组件。
  • Message:Handler接收和处理的消息对象。

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

  • MessageQueue:消息队列,它采用先进先出的方式来管理Message。程序创建Looper对象时,会在它的构造器中创建MessageQueue对象。

Handler的作用有两个——发送消息和处理消息,程序使用Handler发送消息,由Handler发送的消息必须被送到指定的MessageQueue。也就是说当前线程必须要有一个MessageQueue,不过MessageQueue是由Looper负责管理的。如果希望Handler正常工作,必须在当前线程中有一个Looper对象。为了保证当前线程中有Looper对象,可以分如下两种情况处理。
  • 主UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就可通过Handler来发送消息、处理消息了。

  • 程序员自己启动的子线程,必须自己创建一个Looper对象,并启动它。创建Looper对象调用它的prepare()方法,调用loop()方法来启动它。

在线程中使用Handler的步骤如下。
  1. 调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。

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

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

接下来看一段程序,该程序的功能是允许用户输入一个数值上限,当用户单击“计算”按钮时,该应用会将该上限数值发送到新启动的线程中,让该线程来计算该范围内的所有质数。

代码示例

public class MainActivity extends Activity {

    static final String UPPER_NUM = "upper";
    EditText et;
    CalThread calThread;

    // 定义一个线程类
    class CalThread extends Thread {
        public Handler handler;

        public void run() {
            Looper.prepare();
            handler = 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>();
                        //计算从2开始、到upper的所有质数
                        outer:
                        for (int i = 2; i <= upper; i++) {
                            for(int j = 2;j <= Math.sqrt(i); j++) {
                                if(i % j == 0)
                                {
                                    continue outer;
                                }
                            }
                            nums.add(i);
                        }
                        //使用Toast显示统计出来的所有质数
                        Toast.makeText(MainActivity.this, nums.toString(), Toast.LENGTH_LONG).show();
                    }
                }
            };
            Looper.loop();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handlerdemo1);
        et = (EditText) findViewById(R.id.et);
        calThread = new CalThread();
        calThread.start();
    }

    public void computer(View v)
    {
        //创建消息
        Message msg = new Message();
        msg.what = 0x123;
        Bundle bundle = new Bundle();
        bundle.putInt(UPPER_NUM, Integer.parseInt(et.getText().toString()));
        msg.setData(bundle);
        //向新线程中的Handler发送消息
        calThread.handler.sendMessage(msg);
    }
}

效果

img_28bd285fa6ddf2d455d0483a6410d3a8.png
Screenshot_20171026-134515.png

提示

尽量避免在UI线程中执行耗时操作。

目录
相关文章
|
缓存 Java Shell
Handler 的 Message 实例怎么获得?为什么不是直接 new?
Handler 的 Message 实例怎么获得?为什么不是直接 new?
|
消息中间件 存储 项目管理
handler+message【消息机制】
handler+message【消息机制】
136 0
handler+message【消息机制】
|
JSON 数据格式
09准备将Handler的返回值写入ServletResponse
在RequestMappingHandlerAdapter初始化完成后设置默认的HandlerMethodReturnValueHandler HandlerMethodReturnValueHandler体系介绍 HandlerMethodReturnValueHandler的执行流程
181 0
|
消息中间件 存储 Java
你真的了解Handler吗
今天发一个以前的文章,关于Handler的全面解析,大家看看吧~「周末愉快」!
161 0
你真的了解Handler吗
|
Unix 调度 索引
I/O Handler的管理(3)
I/O Handler的管理(3)
93 0
|
消息中间件 Android开发
【Android 异步操作】手写 Handler ( Handler 发送与处理消息 | Handler 初始化 | 完整 Handler 代码 )
【Android 异步操作】手写 Handler ( Handler 发送与处理消息 | Handler 初始化 | 完整 Handler 代码 )
124 0
|
消息中间件 存储 机器学习/深度学习
【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )(二)
【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )(二)
111 0
|
Android开发
|
消息中间件 Android开发 调度