利用RXAndroid优雅地实现事件总线(续)进一步解耦和减小代码量

主要改变的就是HandlerFactory和RXBus这两个类,又加了几个方法,这一次使用到了反射。java

其余的类没有改变,在上一篇文章中均可以找到源码。android

新的RxBus以下所示(仍是基于网上其余人的改的):数组

package com.mitnick.root.mycample.util.rxbus;

import android.util.Log;

import com.mitnick.root.mycample.util.rxbus.responslink.ResponseNode;

import rx.Observable;
import rx.Subscription;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.subjects.PublishSubject;
import rx.subjects.SerializedSubject;
import rx.subjects.Subject;

/**
 * Created by root on 16-4-12.
 * 事件体只会被发射到相对应的主题的订阅者
 */
public class RxBus {
    private static volatile RxBus defaultInstance;
    // 主题
    private final Subject bus;
    public RxBus() {
        bus = new SerializedSubject<>(PublishSubject.create());
    }
    // 单例RxBus
    public static RxBus getDefault() {
        RxBus rxBus = defaultInstance;
        if (defaultInstance == null) {
            synchronized (RxBus.class) {
                rxBus = defaultInstance;
                if (defaultInstance == null) {
                    rxBus = new RxBus();
                    defaultInstance = rxBus;
                }
            }
        }
        return rxBus;
    }

    /**
     * 事件总线发射一个事件
     * @Param rxBusEvent : 事件体
     * */
    public void post (RxBusEvent rxBusEvent) {
        bus.onNext(rxBusEvent);
    }

    /**
     * 订阅事件总线的某一个主题
     * @Param tag : 订阅的主题,事件总线只会对感兴趣的主题发射事件
     * @Param eventType : 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
     * */
    public <T> Observable<T> toObserverable (Class<T> eventType) {
        return bus.ofType(eventType);
//        这里感谢小鄧子的提醒: ofType = filter + cast
//        return bus.filter(new Func1<Object, Boolean>() {
//            @Override
//            public Boolean call(Object o) {
//                return eventType.isInstance(o);
//            }
//        }) .cast(eventType);
    }

    public static Subscription subscription(final String[] tags, final ResponseNode responseNode){
        return getDefault().toObserverable(RxBusEvent.class)
                .filter(new Func1<RxBusEvent, Boolean>() {
                    @Override
                    public Boolean call(RxBusEvent rxBusEvent) {
                        for(String tag : tags){
                            if(rxBusEvent.getTag().equals(tag)){
                                return true;
                            }
                        }
                        return false;
                    }
                })
                .subscribe(new Action1<RxBusEvent>() {
                               @Override
                               public void call(final RxBusEvent rxBusEvent) {
                                   responseNode.operator(rxBusEvent);//开启职责链处理事件
                               }
                           },
                        new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                // TODO: 处理异常
                                Log.e("事件总线",throwable.toString());
                            }
                        });
    }
}

新的HandlerFactory以下所示:app

package com.mitnick.root.mycample.util.rxbus.responslink;


import android.content.Context;
import android.util.Log;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * Created by root on 16-5-17.
 */
public class HandlerFactory {
    /**
     * 获得一个空的职责链处理节点
     * @return responseNode 一个空的职责链处理节点
     * */
    public static ResponseNode getHandler(){
        return new ResponseNode(new DoSomthing(null) {
            @Override
            public boolean dosomthing() {
                return false;
            }
        });
    }

    /**
     * @param c 用于反射方法
     * @param context 传入一个Activity用于回调方法
     * @param events 须要分开处理的事件名称
     * @return responseNode
     *
     * */
    public static ResponseNode getHandler(final Class<?> c,
                                          final Context context,
                                          String[] events){
        ResponseNode responseNode = getHandler();
        ResponseNode buffer = responseNode;
        for(final String event : events){
            buffer = buffer.setHandler(new ResponseNode(new DoSomthing(event) {
                @Override
                public boolean dosomthing() {
                    try {
                        Method method = c.getMethod(event);
                        method.invoke(context);
                        context.getClass().getMethod(event);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e("HandlerFactory",e.toString());
                        return filter();
                    }
                    return filter();
                }
            }));
        }
        buffer.setHandler(responseNode);//循环职责链
        return responseNode;
    }

    /**
     * @param context 传入一个Activity用于回调方法
     * @param events 须要分开处理的事件名称
     * @return responseNode
     *
     * */
    public static ResponseNode getHandler(final Context context,
                                          String[] events){
        ResponseNode responseNode = getHandler();
        ResponseNode buffer = responseNode;
        for(final String event : events){
            buffer = buffer.setHandler(new ResponseNode(new DoSomthing(event) {
                @Override
                public boolean dosomthing() {
                    try {
                        Method method = context.getClass().getMethod(event);
                        method.invoke(context);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e("HandlerFactory",e.toString());
                        return filter();
                    }
                    return filter();
                }
            }));
        }
        buffer.setHandler(responseNode);//循环职责链
        return responseNode;
    }

    /**
     * @param context 传入一个Activity用于回调方法
     * @param events 须要分开处理的事件名称
     * @param eventMap 事件名称的一个转换,总线消息发送者无需知道接受者要回调哪一个函数来实现
     * @return responseNode
     * */
    public static ResponseNode getHandler(final Context context,
                                          String[] events,
                                          final Map<String, String> eventMap){
        ResponseNode responseNode = getHandler();
        ResponseNode buffer = responseNode;
        for(final String event : events){
            buffer = buffer.setHandler(new ResponseNode(new DoSomthing(event) {
                @Override
                public boolean dosomthing() {
                    try {
                        String buffer = event;
                        if(eventMap.containsKey(event)){
                            buffer = eventMap.get(event);
                        }
                        Method method = context.getClass().getMethod(buffer);
                        method.invoke(context);
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e("HandlerFactory",e.toString());
                        return filter();
                    }
                    return filter();
                }
            }));
        }
        buffer.setHandler(responseNode);//循环职责链
        return responseNode;
    }
}

下面来看一下如何注册事件:ide

//订阅事件总线并使用职责链处理
        HashMap<String,String> reflact = new HashMap<>();
        reflact.put("one","loginSuccess");
        rxSubscription = RxBus.subscription(
                new String[]{"loginModel"},
                HandlerFactory.getHandler(
                        this,
                        new String[]{"one", "loginFailed"},
                        reflact
                )
        );

对,就是如此的简单!函数

基本原理是这样的,经过HandlerFactory得到职责链处理节点。HandlerFactory.getHandler的第一个参数是this,反射的回调须要用到this。第二个参数是一个String数组,这个数组的每个元素就是每个感兴趣的事件(能够有多个事件哦)。第三个参数是一个Map,是这样考虑的:由于我要实现高度的解耦,因此Model发送的每个事件都不会知道将会由谁来处理,可是在事件接受方须要将每个事件的每个动做(event)来经过反射映射到相应的处理函数(固然这一切都已经被HandlerFactory封装好了),因此须要用到这个Map来作一下映射,固然,若是event与处理函数同名,那么就只须要使用它的只有前两个参数的重载函数就能够了。post

固然,它也能够同时观察多个事件源,RxBus.subscription的第一个参数是一个String数组,它就是来存放事件源的。测试

下面再来看一下如何发送事件:this

RxBus.getDefault().post(new RxBusEvent("loginModel","one",null));

发送事件也是如此的简单!spa

下面来看一个具体的实现:

package com.mitnick.root.mycample;

import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.transition.Explode;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.mitnick.root.mycample.bean.user.User;
import com.mitnick.root.mycample.util.rxbus.RxBus;
import com.mitnick.root.mycample.util.rxbus.RxBusEvent;
import com.mitnick.root.mycample.util.rxbus.responslink.HandlerFactory;

import java.util.HashMap;

import butterknife.Bind;
import butterknife.ButterKnife;
import me.james.biuedittext.BiuEditText;
import rx.Subscription;

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {


    @Bind(R.id.userName)
    BiuEditText userName;
    @Bind(R.id.userPsw)
    BiuEditText userPsw;
    @Bind(R.id.login)
    Button login;
    @Bind(R.id.verify)
    TextView verify;
    @Bind(R.id.imageView3)
    ImageView baidu;
    @Bind(R.id.imageView2)
    ImageView weixin;
    @Bind(R.id.imageView)
    ImageView qq;
    @Bind(R.id.progressBar4)
    ProgressBar progress;

    private Subscription rxSubscription = null;//订阅RxBus事件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 容许使用transitions
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);
    }

    private void init() {
        setTitle("登陆");
        login.setOnClickListener(this);
        verify.setOnClickListener(this);
        qq.setOnClickListener(this);
        weixin.setOnClickListener(this);
        baidu.setOnClickListener(this);
        // 设置一个exit transition
        getWindow().setExitTransition(new Explode());//new Slide()  new Fade()

        //订阅事件总线并使用职责链处理
        HashMap<String,String> reflact = new HashMap<>();
        reflact.put("one","loginSuccess");
        rxSubscription = RxBus.subscription(
                new String[]{"loginModel"},
                HandlerFactory.getHandler(
                        this,
                        new String[]{"one", "loginFailed"},
                        reflact
                )
        );
        RxBus.getDefault().post(new RxBusEvent("loginModel","one",null));
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(User.getInstence(null,null).isLogin()){
            finish();
        }
        init();
    }

    @Override
    protected void onPause() {
        if(!rxSubscription.isUnsubscribed()){
            rxSubscription.unsubscribe();
        }
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        ButterKnife.unbind(this);
        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.login:
                login.setText("");
                progress.setVisibility(View.VISIBLE);
                break;
            case R.id.imageView:
                break;
            case R.id.imageView2:
                break;
            case R.id.imageView3:
                break;
        }
    }

    public void loginSuccess(){
        User.getInstence(userName.getText().toString(),userPsw.getText().toString());
        startActivity(new Intent(LoginActivity.this, MainActivity.class),
                ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
    }

    public void loginFailed(){
        login.setText("登陆");
        progress.setVisibility(View.INVISIBLE);
    }
}

在这个具体实现样例代码中,由于为了测试,我就在订阅了事件总线以后马上又本身向事件总线发送了一条事件。loginSuccess函数和loginFailed函数就是经过反射机制来回调的。

相关文章
相关标签/搜索