Android开发之Handler消息传递机制总结

Android开发之Handler消息传递机制总结

Handler消息传递机制:主要用于对异步任务的消息处理机制;

Handler工作原理:当任务发出消息时,会将所发的消息压入消息队列(队列:先进先出)中,然后通过轮询的方式对队列里面的消息逐一取出,并在handleMessage事件中对取出的消息进行监听,然后做出相应的处理, 这种机制通常用来处理相对耗时比较长的操作。如下图所示:

Handler应用场景:在Android开发中,一些耗时的操作一般会放入其他线程内运行,这样可防止堵塞主线程运行;但是由于线程安全机制,开启的其他线程不能直接操作UI;UI操作只能在主线程(也称之为UI线程)内进行操作;如果其他线程内的任务想修改UI,那怎么办呢?不慌:通过Handler消息传递机制来通知主线程对UI进行修改;

Handler使用案例:短信验证码发送的倒计时功能,效果图如下:

这里不涉及对上述Demo中UI布局的介绍,只说明倒计时功能实现的具体操作:

倒计时功能,主要用到了Thread和Handler这两个类,同时还涉及一些弱引用的概念;弱引用Activity主要为了GC(垃圾回收机制)对Activity进行回收;

在使用之前先大概了解下弱引用,在Android中通过WeakReference来对引入的Activity进行弱引用;

为什么要用弱引用?

Java的垃圾回收机制(GC)对于对象回收的条件:1.对象没有没有被引用;2.GC处于运行状态;

如果在Handler类中直接引入Activity,由于Handler处于运行状态,导致Activity仍然处于应用状态,GC无法回收Activity,容易导致内存泄漏;

WeakReference原理:当一个对象被WeakReference指向,而没有其他非WeakReference(强引用)指向时,就会被GC给回收;在使用被WeakReference指向的对象时,需要先判断该对象是否已经被回收;

WeakReference wk=new WeakReference<>(Object); //Object是自定义的对象
if(wk.get() != null){ //判断引用的对象有没有被回收
    //dosometime
}

if(wk.get() != null){ } //通过WeakReference类的get实例方法来判断对象是否被回收

WeakReference特点:它何时被回收是不可确定的, 因为这是由GC运行的不确定性所确定的. 所以, 一般用weak reference引用的对象是有价值被cache, 而且很容易被重新被构建, 且很消耗内存的对象;

声明MyHandler类并继承Handler类,同时对Handler中的handleMessage方法进行重写;代码如下:

package com.utils;

import android.app.Activity;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.RequiresApi;
import android.widget.Button;

import com.foodie.pver.titlefoodie.R;

import java.lang.ref.WeakReference;


public class MyHandler extends Handler {
    WeakReference<Activity> wr;
    private Button yzm_btn_text;
    public MyHandler(Activity activity,int reid){
        wr=new WeakReference<>(activity); //对activity进行弱引用,防止Activity未被垃圾回收机制GC回收
        yzm_btn_text=activity.findViewById(reid); //获取需要操作的控件,也就是验证码Button控件
    }
    @Override
    public void handleMessage(Message msg){//重写Handler类中的handleMessage()
        super.handleMessage(msg);
        Activity activity=wr.get();
        if(activity != null){   //判断弱引用是否存在
            switch (msg.what){ //msg.what标识设置
                case 0x00:
                    yzm_btn_text.setClickable(false);
                    yzm_btn_text.setBackgroundResource(R.drawable.no_activity);
                    yzm_btn_text.setText(String.format("已发送%ss", String.valueOf(msg.arg1)).toLowerCase());
                    break;
                case 0x01:
                    yzm_btn_text.setClickable(true);
                    yzm_btn_text.setBackgroundResource(R.drawable.yes_activity);
                    yzm_btn_text.setText("重新获取");
                    break;
                    default:
                        break;
            }
        }
    }
}

MyHandler类继承Handler类,注意Android中Handler引入的包是Android.os.Handler,而不是Java方面的Handler包;同时重写handleMessage()方法监听handler发送过来的数据,并作出相应的处理;在这里Handler处于主线程位置,所以可以对Android中的UI控件进行修改;

上面监听消息的功能有了,接下来就要对开启在其他线程里面的任务来发送消息给Handler消息队列;

public void startTimeNum(final int num){
        new Thread(){
            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void run(){
                super.run();
                for(int i=num;i>=0;i--){
                    Message mes = obtainMessage();
                    mes.arg1 = i;
                    mes.what = 0x00;//计时中的标志
                    sendMessage(mes);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Message mes = obtainMessage();
                mes.what = 0x01;//计时中的标志
                sendMessage(mes);
            }
        }.start();
    }

以上代码中主要有3点:1.通过Thread开启线程;2.obtainMessage()方法主要是用来获取Message对象,然后发送数据;3.通过Thread.sleep()方法设置延时;

获取Message对象的方式有3种:

1.通过new Message()实例化构造函数获取对象;

2.通过obtain()方法获取对象;

3.通过obtainMessage()方法获取对象;

获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(), 这样是从一个可回收对象池中获取Message对象。

总结:通过obtain()方法获取对象,就是从整个Messge池中返回一个新的Message实例,在许多情况下使用它,因为它能避免分配新的对象,从而减少内存的开销了。

猜你喜欢

转载自blog.csdn.net/u012475786/article/details/86609340