diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml new file mode 100644 index 0000000..9d5b48d --- /dev/null +++ b/.idea/checkstyle-idea.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/example/kingja/rxbus/FragmentA.java b/app/src/main/java/example/kingja/rxbus/FragmentA.java index 906a072..9bf666e 100644 --- a/app/src/main/java/example/kingja/rxbus/FragmentA.java +++ b/app/src/main/java/example/kingja/rxbus/FragmentA.java @@ -3,6 +3,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,6 +12,7 @@ import com.kingja.rxbus2.Callback; import com.kingja.rxbus2.RxBus; +import com.kingja.rxbus2.Subscribe; /** * Description:TODO @@ -27,7 +29,7 @@ public class FragmentA extends Fragment { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - + RxBus.getDefault().register(this); rootView = inflater.inflate(R.layout.fragment_a, container, false); return rootView; } @@ -70,17 +72,14 @@ public void onClick(View v) { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - RxBus.getDefault().register(this, EventA.class, new Callback() { - @Override - public void onReceive(EventA event) { - ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); - } - }); - RxBus.getDefault().register(this, EventC.class, new Callback() { - @Override - public void onReceive(EventC event) { - ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); - } - }); + + } + @Subscribe + public void receiveEventA(EventA event) { + ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); + } + @Subscribe + public void receiveEventC(EventC event) { + ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); } } diff --git a/app/src/main/java/example/kingja/rxbus/FragmentB.java b/app/src/main/java/example/kingja/rxbus/FragmentB.java index 957f623..47e936e 100644 --- a/app/src/main/java/example/kingja/rxbus/FragmentB.java +++ b/app/src/main/java/example/kingja/rxbus/FragmentB.java @@ -11,6 +11,7 @@ import com.kingja.rxbus2.Callback; import com.kingja.rxbus2.RxBus; +import com.kingja.rxbus2.Subscribe; /** * Description:TODO @@ -50,17 +51,14 @@ public void onClick(View v) { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - RxBus.getDefault().register(this, EventB.class, new Callback() { - @Override - public void onReceive(EventB event) { - ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); - } - }); - RxBus.getDefault().register(this, EventC.class, new Callback() { - @Override - public void onReceive(EventC event) { - ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); - } - }); + RxBus.getDefault().register(this); + } + @Subscribe + public void receiveEventB(EventB event) { + ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); + } + @Subscribe + public void receiveEventC(EventC event) { + ((TextView) rootView.findViewById(R.id.tv_eventMsg)).setText(event.getMsg()); } } diff --git a/app/src/main/java/example/kingja/rxbus/MainActivity.java b/app/src/main/java/example/kingja/rxbus/MainActivity.java index 783e980..4c9c49b 100644 --- a/app/src/main/java/example/kingja/rxbus/MainActivity.java +++ b/app/src/main/java/example/kingja/rxbus/MainActivity.java @@ -11,6 +11,7 @@ import com.kingja.rxbus2.Callback; import com.kingja.rxbus2.RxBus; +import com.kingja.rxbus2.Subscribe; public class MainActivity extends AppCompatActivity { private final String TAG = getClass().getSimpleName(); @@ -24,13 +25,7 @@ protected void onCreate(Bundle savedInstanceState) { getSupportFragmentManager().beginTransaction().add(R.id.fl_fragmentA, new FragmentA()).commit(); getSupportFragmentManager().beginTransaction().add(R.id.fl_fragmentB, new FragmentB()).commit(); - - RxBus.getDefault().register(this, EventMain.class, new Callback() { - @Override - public void onReceive(EventMain event) { - ((TextView) findViewById(R.id.tv_main_eventMsg)).setText(event.getMsg()); - } - }); + RxBus.getDefault().register(this); } public void sendEventA(View view) { @@ -45,4 +40,9 @@ public void sendEventC(View view) { RxBus.getDefault().post(new EventC(this)); } + @Subscribe + public void receiveEventMain(EventMain event) { + ((TextView) findViewById(R.id.tv_main_eventMsg)).setText(event.getMsg()); + } + } diff --git a/rxbus2/src/main/java/com/kingja/rxbus2/MethodFinder.java b/rxbus2/src/main/java/com/kingja/rxbus2/MethodFinder.java new file mode 100644 index 0000000..a93deb2 --- /dev/null +++ b/rxbus2/src/main/java/com/kingja/rxbus2/MethodFinder.java @@ -0,0 +1,52 @@ +package com.kingja.rxbus2; + +import android.util.Log; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Description:TODO + * Create Time:2017/4/13 15:27 + * Author:KingJA + * Email:kingjavip@gmail.com + */ +public class MethodFinder { + private static final int BRIDGE = 0x40; + private static final int SYNTHETIC = 0x1000; + private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>(); + private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; + + public List findMehod(Class subscriberClass) { + List subscriberMethods = METHOD_CACHE.get(subscriberClass); + if (subscriberMethods != null) { + return subscriberMethods; + } + subscriberMethods = findByReflect(subscriberClass); + return subscriberMethods; + } + + private List findByReflect(Class subscriberClass) { + List subscriberMethods = new ArrayList<>(); + Method[] methods = subscriberClass.getDeclaredMethods(); + for (Method method : methods) { + int modifiers = method.getModifiers(); + if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length == 1) { + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null) { + ThreadMode threadMode = subscribeAnnotation.threadMode(); + Class eventType = parameterTypes[0]; + subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode)); + } + } + } + } + return subscriberMethods; + } +} diff --git a/rxbus2/src/main/java/com/kingja/rxbus2/RxBus.java b/rxbus2/src/main/java/com/kingja/rxbus2/RxBus.java index e865437..295a1fc 100644 --- a/rxbus2/src/main/java/com/kingja/rxbus2/RxBus.java +++ b/rxbus2/src/main/java/com/kingja/rxbus2/RxBus.java @@ -1,12 +1,11 @@ package com.kingja.rxbus2; -import android.content.Context; -import android.util.Log; - +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import io.reactivex.Scheduler; import io.reactivex.android.schedulers.AndroidSchedulers; @@ -14,6 +13,7 @@ import io.reactivex.functions.Consumer; import io.reactivex.processors.FlowableProcessor; import io.reactivex.processors.PublishProcessor; +import io.reactivex.schedulers.Schedulers; /** * Description:TODO @@ -26,6 +26,7 @@ public class RxBus { private final FlowableProcessor mFlowableProcessor; private static RxBus mRxBus; private static Map, Map, Disposable>> mDisposableMap = new HashMap<>(); + private final MethodFinder mMethodFinder; /** * Wraps this Subject and serializes the calls to the onSubscribe, onNext, onError and onComplete methods, making @@ -33,6 +34,7 @@ public class RxBus { */ private RxBus() { mFlowableProcessor = PublishProcessor.create().toSerialized(); + mMethodFinder = new MethodFinder(); } public static RxBus getDefault() { @@ -52,28 +54,71 @@ public void post(Object obj) { } } - public void register(Object subscriber, Class eventType, final Callback callback) { - register(subscriber, eventType, callback, AndroidSchedulers.mainThread()); + public void register(Object subsciber) { + Class subsciberClass = subsciber.getClass(); + List subscriberMethods = mMethodFinder.findMehod(subsciberClass); + for (SubscriberMethod subscriberMethod : subscriberMethods) { + addSubscriber(subsciber, subscriberMethod); + } } - public void register(Object subscriber, Class eventType, final Callback callback, Scheduler scheduler) { - Disposable disposable = mFlowableProcessor.ofType(eventType).observeOn(scheduler).subscribe(new Consumer() { + private void addSubscriber(final Object subsciber, final SubscriberMethod subscriberMethod) { + Class subsciberClass = subsciber.getClass(); + Class eventType = subscriberMethod.getEventType(); + Scheduler threadMode = getThreadMode(subscriberMethod.getThreadMode()); + Disposable disposable = mFlowableProcessor.ofType(eventType).observeOn(threadMode).subscribe(new Consumer() { @Override - public void accept(T t) throws Exception { - callback.onReceive(t); + public void accept(Object o) throws Exception { + invokeMethod(subsciber, subscriberMethod, o); } }); - Class subscriberClass = subscriber.getClass(); - Map, Disposable> disposableMap = mDisposableMap.get(subscriberClass); + Map, Disposable> disposableMap = mDisposableMap.get(subsciberClass); if (disposableMap == null) { disposableMap = new HashMap<>(); - mDisposableMap.put(subscriberClass, disposableMap); + mDisposableMap.put(subsciberClass, disposableMap); } disposableMap.put(eventType, disposable); } - public void unRegister(Object subscriber, Class eventType) { + private Scheduler getThreadMode(ThreadMode threadMode) { + Scheduler scheduler; + switch (threadMode) { + case MAIN: + scheduler = AndroidSchedulers.mainThread(); + break; + case IO: + scheduler = Schedulers.io(); + break; + case COMPUTATION: + scheduler = Schedulers.computation(); + break; + case SINGLE: + scheduler = Schedulers.single(); + break; + case TRAMPOLINE: + scheduler = Schedulers.trampoline(); + break; + case NEW_THREAD: + scheduler = Schedulers.newThread(); + break; + default: + scheduler = AndroidSchedulers.mainThread(); + break; + } + return scheduler; + } + private void invokeMethod(Object subsciber, SubscriberMethod subscriberMethod, Object obj) { + try { + subscriberMethod.method.invoke(subsciber, obj); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + public void unRegister(Object subscriber, Class eventType) { Class subscriberClass = subscriber.getClass(); Map, Disposable> disposableMap = mDisposableMap.get(subscriberClass); if (disposableMap == null) { diff --git a/rxbus2/src/main/java/com/kingja/rxbus2/Subscribe.java b/rxbus2/src/main/java/com/kingja/rxbus2/Subscribe.java new file mode 100644 index 0000000..97267f5 --- /dev/null +++ b/rxbus2/src/main/java/com/kingja/rxbus2/Subscribe.java @@ -0,0 +1,20 @@ +package com.kingja.rxbus2; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Description:TODO + * Create Time:2017/5/26 14:40 + * Author:KingJA + * Email:kingjavip@gmail.com + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Subscribe { + ThreadMode threadMode() default ThreadMode.MAIN; +} diff --git a/rxbus2/src/main/java/com/kingja/rxbus2/SubscriberMethod.java b/rxbus2/src/main/java/com/kingja/rxbus2/SubscriberMethod.java new file mode 100644 index 0000000..884ba6a --- /dev/null +++ b/rxbus2/src/main/java/com/kingja/rxbus2/SubscriberMethod.java @@ -0,0 +1,33 @@ +package com.kingja.rxbus2; + +import java.lang.reflect.Method; + +/** + * Description:TODO + * Create Time:2017/4/13 15:28 + * Author:KingJA + * Email:kingjavip@gmail.com + */ +public class SubscriberMethod { + public ThreadMode getThreadMode() { + return threadMode; + } + + final ThreadMode threadMode; + final Method method; + final Class eventType; + + public SubscriberMethod(Method method, Class eventType,ThreadMode threadMode) { + this.method = method; + this.eventType = eventType; + this.threadMode = threadMode; + } + + public Method getMethod() { + return method; + } + + public Class getEventType() { + return eventType; + } +} diff --git a/rxbus2/src/main/java/com/kingja/rxbus2/Subscription.java b/rxbus2/src/main/java/com/kingja/rxbus2/Subscription.java new file mode 100644 index 0000000..3c28927 --- /dev/null +++ b/rxbus2/src/main/java/com/kingja/rxbus2/Subscription.java @@ -0,0 +1,17 @@ +package com.kingja.rxbus2; + +/** + * Description:TODO + * Create Time:2017/4/13 15:56 + * Author:KingJA + * Email:kingjavip@gmail.com + */ +public class Subscription { + final Object subscriber; + final SubscriberMethod subscriberMethod; + + Subscription(Object subscriber, SubscriberMethod subscriberMethod) { + this.subscriber = subscriber; + this.subscriberMethod = subscriberMethod; + } +} diff --git a/rxbus2/src/main/java/com/kingja/rxbus2/ThreadMode.java b/rxbus2/src/main/java/com/kingja/rxbus2/ThreadMode.java new file mode 100644 index 0000000..add881c --- /dev/null +++ b/rxbus2/src/main/java/com/kingja/rxbus2/ThreadMode.java @@ -0,0 +1,13 @@ +package com.kingja.rxbus2; + +import io.reactivex.Scheduler; + +/** + * Description:TODO + * Create Time:2017/5/26 14:47 + * Author:KingJA + * Email:kingjavip@gmail.com + */ +public enum ThreadMode { + SINGLE, COMPUTATION, IO, TRAMPOLINE, NEW_THREAD,MAIN +}