手动模拟EventBus框架

一、实现原理

1、主要的实现类为EventBus类,用观察者实际模式来实现(观察者设计模式参考),包含三个主要的方法:register、 unregister、post

2、订阅者(一般为activity)通过EventBus的register和unRegister来订阅和取消订阅

3、事件发布者通过post来发布数据,EventBus找到自己缓存的所有订阅者,并找到每一个订阅者的所有方法并执行

二、订阅

1、activity把自己作为订阅者,注册到EventBus中,当事件产生时,会调用activity中指定的方法。为了能准确找到需要被调用的方法,这里需要用到自定义注解。
(1)、注册订阅者,activity的onCreate中调用 EventBus.getDefault().register(this);
(2)、自定义注解的实现

@Target({ElementType.METHOD})   // 注解用到方法上的
@Retention(RetentionPolicy.RUNTIME) // 运行时起作用
public @interface Subscrible {
    ThreadMode threadMode() default ThreadMode.MAIN;
}

(3)、订阅者方法的实现

    // MainActivity方法放到eventbus中,
    // 并不是所有的方法都放进EventBus中
    // 而是所有带有自定义注解的方法都放进去
    @Subscrible(threadMode = ThreadMode.MAIN)
    public void test1(EventBean eb){
        Log.d("lixm","MainActivity a ====> EventBean = " + eb);
    }

    @Subscrible(threadMode = ThreadMode.BACKGROUND)
    public void test2(EventBean eb){
        Log.d("lixm","MainActivity b ====> EventBean = " + eb);
    }

    // 测试,这个参数不符合,不能接收到数据
    @Subscrible(threadMode = ThreadMode.MAIN)
    public void test3(String str){
        Log.d("lixm","MainActivity b ====> String = " + str);
    }

(4)、EventBus中订阅的实现
EventBus维护一个HashMap对象,key是订阅者对象,value是订阅者对象中带有自定义注解的方法的集合。

三、事件发送

1、事件发送者调用EventBus的post方法
EventBus.getDefault().post(new EventBean(“M1”,“M2”));

2、发送方法的实现
EventBus遍历订阅者集合(hashmap),并取出每一个订阅者的方法的集合,循环执行

四、具体的代码实现

1、订阅者(兼事件发送者)activity

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.hisign.android.test.R;

public class MainActivity extends Activity {

    @Override
    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event_bus_main);
        EventBus.getDefault().register(this);


        findViewById(R.id.btAsync).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new EventBean("M1","M2"));
            }
        });

        findViewById(R.id.btGo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    // MainActivity方法放到eventbus中,
    // 并不是所有的方法都放进EventBus中
    // 而是所有带有自定义注解的方法都放进去
    @Subscrible(threadMode = ThreadMode.MAIN)
    public void test1(EventBean eb){
        Log.d("lixm","MainActivity a ====> EventBean = " + eb);
    }

    @Subscrible(threadMode = ThreadMode.BACKGROUND)
    public void test2(EventBean eb){
        Log.d("lixm","MainActivity b ====> EventBean = " + eb);
    }

    // 测试,这个参数不符合,不能接收到数据
    @Subscrible(threadMode = ThreadMode.MAIN)
    public void test3(String str){
        Log.d("lixm","MainActivity b ====> String = " + str);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //EventBus.getDefault().unRegister(this);
    }
}

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.hisign.android.test.R;

public class SecondActivity extends Activity {

    @Override
    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event_bus_second);
        EventBus.getDefault().register(this);
        findViewById(R.id.btAsync).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 这里可以模拟网络加载数据(异步进行)
                EventBus.getDefault().post(new EventBean("2-1","2-2"));
            }
        });
    }

    @Subscrible(threadMode=ThreadMode.MAIN)
    public void a(EventBean eventBean){
        // 得到数据来自异步线程,需要在主线程更新UI
        Log.d("lixm","SecondActivity a ====> EventBean = " + eventBean);
    }
}

2、重点:EventBus实现

import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 管理类,负责将某个activity的方法添加到其中,其他的activity可以在里面寻找方法并调用
 */
public class EventBus {

    /**
     * 用于缓存订阅者注册进来的方法
     * Object 订阅者
     * List<SubscribleMethod> 订阅者的方法的集合
     * SubscribleMethod 订阅者的方法的封装类
     */
    private Map<Object, List<SubscribleMethod>> cacheMap;

    private static EventBus instance;

    private EventBus() {
        cacheMap = new HashMap<>();
    }

    public static EventBus getDefault() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    /**
     * 注册,把订阅者(观察者)注册进来
     * @param object 订阅者类
     */
    public void register(Object object) {
        // 寻找object类中,所有带有subscirble注解的方法
        List<SubscribleMethod> list = cacheMap.get(object); //  判断是否订阅
        Log.d("lixm", "register(),list = " + list);
        if (list == null) {
            list = findSubscribleMethods(object);
            Log.d("lixm", "register(),findSubscribleMethods--> list = " + list.toString());
            cacheMap.put(object, list);
        }
    }

    /**
     * 在指定类中查找带有自定义注解的方法
     *
     * @param object 观察者类
     * @return
     */
    private List<SubscribleMethod> findSubscribleMethods(Object object) {
        List<SubscribleMethod> list = new ArrayList<>();
        Class<?> clazz = object.getClass();
        Log.d("lixm", "findSubscribleMethods(),clazz = " + clazz.getName());
        while (clazz != null) {   // 循环找,不但找自己类中的,还要找父类中的
            String className = clazz.getName();
            if (className.startsWith("java.")   //  但如果是系统的类中,肯定没有我们自定义的注解,所以不需要解析
                    || className.startsWith("javax.")
                    || className.startsWith("android.")) {
                break;
            }
            // 得到类中的所有方法
            Method[] methods = clazz.getDeclaredMethods();
            if (methods != null && methods.length > 0) {
                for (Method method : methods) {
                    // 只找带有subscrible注解的方法
                    Subscrible subscrible = method.getAnnotation(Subscrible.class);
                    Log.d("lixm", "method = " + method + ", subscrible = " + subscrible);
                    if (subscrible == null) {
                        continue;
                    }
                    Class<?>[] types = method.getParameterTypes();  // 该对象表示的方法参数的类型
                    if (types != null) {
                        if (types.length != 1) {
                            Log.d("lixm", "only one param");
                        } else {
                            String paramName = types[0].getName();
                            Log.d("lixm", "paramName = " + paramName);
                            if(types[0].getName().equals(EventBean.class.getName())){  //  根据参数的类型来匹配,参数必须是自己指定的类型
                                ThreadMode threadMode = subscrible.threadMode();
                                SubscribleMethod subscribleMethod = new SubscribleMethod();
                                subscribleMethod.setMethod(method);
                                subscribleMethod.setSubscriber(object);   // 指定订阅至
                                subscribleMethod.setThreadMode(threadMode);
                                subscribleMethod.setType(types[0]);
                                list.add(subscribleMethod);
                            }else{
                                Log.d("lixm", "Parameter type error.");
                            }
                        }
                    }
                    clazz = clazz.getSuperclass();
                }
            }
        }
        return list;
    }

    /**
     * 发送数据
     * cacheMap中找到当前保存的所有订阅者
     * 取出每一个订阅者的方法,循环调用执行
     * @param paramObj
     */
    public void post(Object paramObj) {
        // 直接循环cacheMap,找到相应的方法执行
        if (cacheMap != null && cacheMap.size() > 0) {
            Set<Object> set = cacheMap.keySet();
            Iterator<Object> iterator = set.iterator();  //  订阅者的集合
            Log.d("lixm", "post(),iterator = " + iterator);
            while (iterator.hasNext()) {
                Object object = iterator.next();
                List<SubscribleMethod> list = cacheMap.get(object); // 取出每一个订阅者的方法
                if (list == null || list.size() == 0) {
                    return;
                }
                for (SubscribleMethod subscribleMethod : list) {  // 循环执行每一个方法
                    // 判断参数的类型是否一致,列表中保存的参数类型,和传进来的参数类型是否一致
                    if (subscribleMethod.getType().isAssignableFrom(paramObj.getClass())) {
                        invok(subscribleMethod, object, paramObj);
                    }
                }
            }
        }
    }

    /**
     * 方法的执行
     *
     * @param subscribleMethod 要执行方法的封装
     * @param object           观察者(拥有方法的那个类)
     * @param paramObj         要执行方法的参数(post数据的封装)
     */
    private void invok(SubscribleMethod subscribleMethod, final Object object, final Object paramObj) {
        final Method method = subscribleMethod.getMethod();
        try {
            // todo 这里需要判断方法在哪个线程执行?
            if (subscribleMethod.getThreadMode() == ThreadMode.MAIN) {   // 主线程执行
                String mainThreadName = Thread.currentThread().getName() + "-" + Thread.currentThread().getId();
                Log.d("lixm", "run in main thread,threadName = " + mainThreadName);
                method.invoke(object, paramObj);
            } else if (subscribleMethod.getThreadMode() == ThreadMode.BACKGROUND) {  // 在子线程中执行
                new Thread() {
                    public void run() {
                        try {
                            String subThradName = Thread.currentThread().getName() + "-" + Thread.currentThread().getId();
                            Log.d("lixm", "run in sub thread,subThradName = " + subThradName);
                            method.invoke(object, paramObj);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 取消注册
     *
     * @param object
     */
    public void unRegister(Object object) {
        if (object != null) {
            if (cacheMap.containsKey(object)) {
                cacheMap.remove(object);
            }
        }
    }
}

3、订阅者方法的封装类

import java.lang.reflect.Method;

public class SubscribleMethod {
    private Method method;          // 要执行的方法
    private Object subscriber;      // 观察者(订阅者)
    private ThreadMode threadMode;  // 指定方法要执行的线程

    // 方法中的参数类型
    private Class<?> type;

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public void setThreadMode(ThreadMode threadMode) {
        this.threadMode = threadMode;
    }


    public Object getSubscriber() {
        return subscriber;
    }

    public void setSubscriber(Object subscriber) {
        this.subscriber = subscriber;
    }

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }


    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

}

4、自定义注解类


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})   // 注解用到方法上的
@Retention(RetentionPolicy.RUNTIME) // 运行时起作用
public @interface Subscrible {
    ThreadMode threadMode() default ThreadMode.MAIN;
}

5、自定义参数类


public class EventBean {
    private String one;
    private String two;

    public EventBean(String one , String two){
        this.one = one;
        this.two = two;
    }

    public String getOne() {
        return one;
    }

    public void setOne(String one) {
        this.one = one;
    }

    @Override
    public String toString() {
        return "EventBean{" +
                "one='" + one + '\'' +
                ", two='" + two + '\'' +
                '}';
    }
}
public enum ThreadMode {
    MAIN,
    BACKGROUND
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值