Android的消息循环与Handler机制理解 4年前

一、概念

1、事件驱动型

什么是事件驱动?就是有事了才去处理,没事就躺着不动。假如把用户点击按钮,滑动页面等这些都看作事件,事件产生后程序就执行相应的处理方法,就是属于事件驱动型。

2、消息循环

把需要处理的事件表示成一个消息,并且把这个消息放入一个队列。消息循环就是一循环,for或者while都一样。从消息队列里面取出未处理的消息,然后调用该消息的处理方法。

3、Handler

最开始碰到handler是需要在子线程里面更新UI的时候。android的UI更新只能在主线程中进行,但是在子线程中执行的逻辑又需要更新UI,例如文件下载,在子线程中访问网络下载之后,就是更新下载进度。这个时候就需要使用Hanlder,准确的说是要发送一个进度更新的消息。什么是Handler?我的理解是消息的处理者。create消息对应一个create的Handler,destroy消息对应一个destroy的Handler。

二、实现

只是说说概念太假了,下面就来实现一个简单的消息处理机制。

1、Msg

把产生的事件用消息来表示,数据用各个参数传递。

public class Msg implements Serializable{
    //序列化标识
    private static final long serialVersionUID = -2414053244664115328L;
    
    //该消息的处理者。
    private int handlerId;
    
    //参数。
    public Object arg1;
    public Object arg2;

    //大量参数
    public Object array[];
    
    public Msg(int handlerId) {
        this.handlerId=handlerId;
    }
    
    public void setHandlerId(int handlerId) {
        this.handlerId=handlerId;
    }
    public int getHandleId() {
        return handlerId;
    }
}

2、Handler

事件的处理者

public abstract class Handler {
    //唯一标识,由Looper分配
    private int id;
    
    //使用该Handler的Looper
    private Looper looper;
    
    public Handler(Looper looper) {
        this.looper=looper;
        id=looper.addMsgHandler(this);
    }
    
    //消息处理函数
    abstract public  boolean handleMsg(Msg msg);
    
    //添加一个未处理消息。
    public void sendMsg(Msg msg) {
        looper.addMsg(msg);
    }
    
    //返回该handler的信使。
    public Msg obtainMsg() {
        return new Msg(id);
    }
}

3、Looper

消息循环

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

public class Looper {
    private int handlerCount=0;
    //消息队列。
    private Queue<Msg> msgQueue=new LinkedList<Msg>();
    //消息的处理。
    private Map<Integer, Handler> msgHandler=new HashMap<>();
    
    //loop
    public void loop() {
        for(;true;)
            if(!msgQueue.isEmpty())
                if(!distributeMsg(msgQueue.poll()))
                //当消息处理返回false时。程序结束。
                    break;    
    }
    
    //添加处理消息的handler
    public int addMsgHandler(Handler handler) {
        handlerCount++;
        msgHandler.put(handlerCount,handler);
        return handlerCount;
    }
    
    //添加待处理的消息
    public void addMsg(Msg msg) {
        msgQueue.add(msg);
    }
    
    //消息分发
    private boolean distributeMsg(Msg msg) {
        Handler handler=msgHandler.get(msg.getHandleId());
        if(handler!=null) {
            handler.handleMsg(msg);
        }else {
            //出现未知消息,程序结束。
            System.out.println("exit");
            return false;
        }
        return true;    
    }
}

4、模拟生命周期

abstract class Basic{
    private Looper mainLooper=new Looper();
    private Handler sysHandler=new Handler(mainLooper) {
                @Override
                public boolean handleMsg(Msg msg) {
                    if(msg.arg1.equals("create")) {
                        onCreate();
                    }
                    if(msg.arg1.equals("destroy")) {
                        onDestroy();
                    }
                    return true;
                }
            };
    
    public Basic() {
        Msg m=sysHandler.obtainMsg();
        m.arg1="create";
        sysHandler.sendMsg(m);
        //新获取一个Msg,不能沿用上一个。
        m=sysHandler.obtainMsg();
        m.arg1="destroy";
        sysHandler.sendMsg(m);
    }
    
    public Looper getMainLooper() {
        return mainLooper;
    }
    
    /**
     * 生命周期
     */
    abstract public void onCreate();
    abstract public void onDestroy();
}

上面的代码创建了一个抽象类Basic,在里面注册了一个处理create和destroy两个消息的Handler。

5、子线程调用主线程的方法。

public class Main extends Basic{
    private final Handler handler
        =new Handler(getMainLooper()) {
        @Override
        public boolean handleMsg(Msg msg) {
            // TODO Auto-generated method stub
            System.out.println("msg.arg1="+msg.arg1+",Tid="+
            Thread.currentThread().getId());
            getMainLooper().addMsg(new Msg(-1));
            return true;
        }
    };
    public void onCreate() {
        System.out.println("..............onCreate");
        System.out.println("mainThread Tid="+Thread.currentThread().getId());
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("childThread Tid="+Thread.currentThread().getId());
                Msg msg=handler.obtainMsg();
                msg.arg1="childCall";
                handler.sendMsg(msg);
            }
        }).start();
    }
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        System.out.println(".............onDestroy");
        //getMainLooper().addMsg(new Msg(-1));
    }
    public static void main(String[] args) {
        new Main().getMainLooper().loop();
    }
}

6、结果

结果分析,首先是两个生命周期的方法被调用,其次是实现了子线程调用主线程的方法。这里子线程转到主线程的原因是因为Looper运行在主线程,消息由Looper分发处理。

image
Fallen glory
世界上有很多真实的爱情,它们发生的时候都是真的,但让人悲伤的是,它们改变的时候、消失的时候,也是真的。
3
发布数
0
关注者
1529
累计阅读

热门教程文档

Linux
51小节
Golang
23小节
Typescript
31小节
Spring Boot
24小节
C
14小节
广告