利用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函數就是經過反射機制來回調的。

相關文章
相關標籤/搜索