Commit fffb7f32 by zhengnw@sobot.com

widget 1.1.3 添加livedata 事件总线

parent 7a5ea746
......@@ -13,7 +13,7 @@ ext {
PUBLISH_GROUP_ID = "com.sobot.library" //项目包名
PUBLISH_ARTIFACT_ID = 'widget' //项目名
// PUBLISH_ARTIFACT_ID = 'widget_x' //项目名
PUBLISH_VERSION = '1.1.2' //版本号
PUBLISH_VERSION = '1.1.3' //版本号
}
......
package android.arch.lifecycle;
import static android.arch.lifecycle.Lifecycle.State.CREATED;
import static android.arch.lifecycle.Lifecycle.State.DESTROYED;
import android.support.annotation.NonNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ExternalLiveData<T> extends MutableLiveData<T> {
public static final int START_VERSION = LiveData.START_VERSION;
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
try {
//use ExternalLifecycleBoundObserver instead of LifecycleBoundObserver
LifecycleBoundObserver wrapper = new ExternalLifecycleBoundObserver(owner, observer);
LifecycleBoundObserver existing = (LifecycleBoundObserver) callMethodPutIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
} catch (Exception e) {
e.printStackTrace();
}
}
public int getVersion() {
return super.getVersion();
}
/**
* determine when the observer is active, means the observer can receive message
* the default value is CREATED, means if the observer's state is above create,
* for example, the onCreate() of activity is called
* you can change this value to CREATED/STARTED/RESUMED
* determine on witch state, you can receive message
*
* @return Lifecycle.State
*/
protected Lifecycle.State observerActiveLevel() {
return CREATED;
}
class ExternalLifecycleBoundObserver extends LifecycleBoundObserver {
ExternalLifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(owner, observer);
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(observerActiveLevel());
}
}
private Object getFieldObservers() throws Exception {
Field fieldObservers = LiveData.class.getDeclaredField("mObservers");
fieldObservers.setAccessible(true);
return fieldObservers.get(this);
}
private Object callMethodPutIfAbsent(Object observer, Object wrapper) throws Exception {
Object mObservers = getFieldObservers();
Class<?> classOfSafeIterableMap = mObservers.getClass();
Method putIfAbsent = classOfSafeIterableMap.getDeclaredMethod("putIfAbsent",
Object.class, Object.class);
putIfAbsent.setAccessible(true);
return putIfAbsent.invoke(mObservers, observer, wrapper);
}
}
package com.sobot.widget.livedatabus;
import android.support.annotation.NonNull;
import com.sobot.widget.livedatabus.core.Config;
import com.sobot.widget.livedatabus.core.LiveEvent;
import com.sobot.widget.livedatabus.core.LiveEventBusCore;
import com.sobot.widget.livedatabus.core.Observable;
import com.sobot.widget.livedatabus.core.ObservableConfig;
public class SobotLiveEventBus {
/**
* get observable by key with type
*
* @param key key
* @param type type
* @param <T> T
* @return Observable
*/
public static <T> Observable<T> get(@NonNull String key, @NonNull Class<T> type) {
return LiveEventBusCore.get().with(key, type);
}
/**
* get observable by key
*
* @param key String
* @param <T> T
* @return Observable
*/
public static <T> Observable<T> get(@NonNull String key) {
return (Observable<T>) get(key, Object.class);
}
/**
* get observable from eventType
*
* @param eventType Class
* @param <T> T
* @return Observable
*/
public static <T extends LiveEvent> Observable<T> get(@NonNull Class<T> eventType) {
return get(eventType.getName(), eventType);
}
/**
* use the inner class Config to set params
* first of all, call config to get the Config instance
* then, call the method of Config to config LiveEventBus
* call this method in Application.onCreate
* @return Config
*/
public static Config config() {
return LiveEventBusCore.get().config();
}
/**
* use the inner class Config to set params
* first of all, call config to get the Config instance
* then, call the method of Config to config LiveEventBus
* call this method in Application.onCreate
* @param key String
* @return Config
*/
public static ObservableConfig config(@NonNull String key) {
return LiveEventBusCore.get().config(key);
}
}
\ No newline at end of file
package com.sobot.widget.livedatabus.core;
import android.content.Context;
import android.support.annotation.NonNull;
import com.sobot.widget.livedatabus.logger.Logger;
import com.sobot.widget.livedatabus.utils.AppUtils;
public class Config {
/**
* lifecycleObserverAlwaysActive
* set if then observer can always receive message
* true: observer can always receive message
* false: observer can only receive message when resumed
*
* @param active boolean
* @return Config
*/
public Config lifecycleObserverAlwaysActive(boolean active) {
LiveEventBusCore.get().setLifecycleObserverAlwaysActive(active);
return this;
}
/**
* @param clear boolean
* @return true: clear livedata when no observer observe it
* false: not clear livedata unless app was killed
*/
public Config autoClear(boolean clear) {
LiveEventBusCore.get().setAutoClear(clear);
return this;
}
/**
* config broadcast
* only if you called this method, you can use broadcastValue() to send broadcast message
*
* @param context Context
* @return Config
*/
public Config setContext(Context context) {
AppUtils.init(context);
LiveEventBusCore.get().registerReceiver();
return this;
}
/**
* setLogger, if not set, use DefaultLogger
*
* @param logger Logger
* @return Config
*/
public Config setLogger(@NonNull Logger logger) {
LiveEventBusCore.get().setLogger(logger);
return this;
}
/**
* set logger enable or disable, default enable
*
* @param enable boolean
* @return Config
*/
public Config enableLogger(boolean enable) {
LiveEventBusCore.get().enableLogger(enable);
return this;
}
}
package com.sobot.widget.livedatabus.core;
/**
* 调试信息控制台
*/
public final class Console {
private Console() {
}
/**
* 获取控制台信息
*
* @return 调试信息
*/
public static String getInfo() {
return LiveEventBusCore.get().console.getConsoleInfo();
}
}
package com.sobot.widget.livedatabus.core;
import java.io.Serializable;
public interface LiveEvent extends Serializable {
}
package com.sobot.widget.livedatabus.core;
import android.app.Application;
import android.arch.lifecycle.ExternalLiveData;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import com.sobot.widget.livedatabus.ipc.core.ProcessorManager;
import com.sobot.widget.livedatabus.ipc.receiver.LebIpcReceiver;
import com.sobot.widget.livedatabus.logger.DefaultLogger;
import com.sobot.widget.livedatabus.logger.Logger;
import com.sobot.widget.livedatabus.logger.LoggerManager;
import com.sobot.widget.livedatabus.utils.AppUtils;
import com.sobot.widget.livedatabus.utils.ThreadUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
/**
* LiveEventBusCore
*/
public final class LiveEventBusCore {
/**
* 单例模式实现
*/
private static class SingletonHolder {
private static final LiveEventBusCore DEFAULT_BUS = new LiveEventBusCore();
}
public static LiveEventBusCore get() {
return SingletonHolder.DEFAULT_BUS;
}
/**
* 存放LiveEvent
*/
private final Map<String, LiveEvent<Object>> bus;
/**
* 可配置的项
*/
private final Config config = new Config();
private boolean lifecycleObserverAlwaysActive;
private boolean autoClear;
private LoggerManager logger;
private final Map<String, ObservableConfig> observableConfigs;
/**
* 跨进程通信
*/
private LebIpcReceiver receiver;
private boolean isRegisterReceiver = false;
/**
* 调试
*/
final InnerConsole console = new InnerConsole();
private LiveEventBusCore() {
bus = new HashMap<>();
observableConfigs = new HashMap<>();
lifecycleObserverAlwaysActive = true;
autoClear = false;
logger = new LoggerManager(new DefaultLogger());
receiver = new LebIpcReceiver();
registerReceiver();
}
public synchronized <T> Observable<T> with(String key, Class<T> type) {
if (!bus.containsKey(key)) {
bus.put(key, new LiveEvent<>(key));
}
return (Observable<T>) bus.get(key);
}
/**
* use the class Config to set params
* first of all, call config to get the Config instance
* then, call the method of Config to config LiveEventBus
* call this method in Application.onCreate
* @return Config
*/
public Config config() {
return config;
}
public ObservableConfig config(String key) {
if (!observableConfigs.containsKey(key)) {
observableConfigs.put(key, new ObservableConfig());
}
return observableConfigs.get(key);
}
void setLogger(@NonNull Logger logger) {
this.logger.setLogger(logger);
}
void enableLogger(boolean enable) {
this.logger.setEnable(enable);
}
void registerReceiver() {
if (isRegisterReceiver) {
return;
}
Application application = AppUtils.getApp();
if (application != null) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(IpcConst.ACTION);
application.registerReceiver(receiver, intentFilter);
isRegisterReceiver = true;
}
}
void setLifecycleObserverAlwaysActive(boolean lifecycleObserverAlwaysActive) {
this.lifecycleObserverAlwaysActive = lifecycleObserverAlwaysActive;
}
void setAutoClear(boolean autoClear) {
this.autoClear = autoClear;
}
private class LiveEvent<T> implements Observable<T> {
@NonNull
private final String key;
private final LifecycleLiveData<T> liveData;
private final Map<Observer, ObserverWrapper<T>> observerMap = new HashMap<>();
private final Handler mainHandler = new Handler(Looper.getMainLooper());
LiveEvent(@NonNull String key) {
this.key = key;
this.liveData = new LifecycleLiveData<>(key);
}
/**
* 进程内发送消息
*
* @param value 发送的消息
*/
@Override
public void post(T value) {
if (ThreadUtils.isMainThread()) {
postInternal(value);
} else {
mainHandler.post(new PostValueTask(value));
}
}
/**
* App内发送消息,跨进程使用
*
* @param value 发送的消息
*/
@Override
public void postAcrossProcess(T value) {
broadcast(value, false, true);
}
/**
* App之间发送消息
*
* @param value 发送的消息
*/
@Override
public void postAcrossApp(T value) {
broadcast(value, false, false);
}
/**
* 进程内发送消息,延迟发送
*
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
@Override
public void postDelay(T value, long delay) {
mainHandler.postDelayed(new PostValueTask(value), delay);
}
/**
* 进程内发送消息,延迟发送,带生命周期
* 如果延时发送消息的时候sender处于非激活状态,消息取消发送
*
* @param owner 消息发送者
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
@Override
public void postDelay(LifecycleOwner owner, final T value, long delay) {
mainHandler.postDelayed(new PostLifeValueTask(value, owner), delay);
}
/**
* 进程内发送消息
* 强制接收到消息的顺序和发送顺序一致
*
* @param value 发送的消息
*/
@Override
public void postOrderly(T value) {
mainHandler.post(new PostValueTask(value));
}
/**
* App之间发送消息
*
* @param value 发送的消息
*/
@Override
@Deprecated
public void broadcast(T value) {
broadcast(value, false, false);
}
/**
* 以广播的形式发送一个消息
* 需要跨进程、跨APP发送消息的时候调用该方法
*
* @param value 发送的消息
* @param foreground true:前台广播、false:后台广播
* @param onlyInApp true:只在APP内有效、false:全局有效
*/
@Override
public void broadcast(final T value, final boolean foreground, final boolean onlyInApp) {
if (AppUtils.getApp() != null) {
if (ThreadUtils.isMainThread()) {
broadcastInternal(value, foreground, onlyInApp);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
broadcastInternal(value, foreground, onlyInApp);
}
});
}
} else {
post(value);
}
}
/**
* 注册一个Observer,生命周期感知,自动取消订阅
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
@Override
public void observe(@NonNull final LifecycleOwner owner, @NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeInternal(owner, observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeInternal(owner, observer);
}
});
}
}
/**
* 注册一个Observer,生命周期感知,自动取消订阅
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
@Override
public void observeSticky(@NonNull final LifecycleOwner owner, @NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeStickyInternal(owner, observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeStickyInternal(owner, observer);
}
});
}
}
/**
* 注册一个Observer,需手动解除绑定
*
* @param observer 观察者
*/
@Override
public void observeForever(@NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeForeverInternal(observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeForeverInternal(observer);
}
});
}
}
/**
* 注册一个Observer,需手动解除绑定
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param observer 观察者
*/
@Override
public void observeStickyForever(@NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
observeStickyForeverInternal(observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
observeStickyForeverInternal(observer);
}
});
}
}
/**
* 通过observeForever或observeStickyForever注册的,需要调用该方法取消订阅
*
* @param observer 观察者
*/
@Override
public void removeObserver(@NonNull final Observer<T> observer) {
if (ThreadUtils.isMainThread()) {
removeObserverInternal(observer);
} else {
mainHandler.post(new Runnable() {
@Override
public void run() {
removeObserverInternal(observer);
}
});
}
}
@MainThread
private void postInternal(T value) {
logger.log(Level.INFO, "post: " + value + " with key: " + key);
liveData.setValue(value);
}
@MainThread
private void broadcastInternal(T value, boolean foreground, boolean onlyInApp) {
logger.log(Level.INFO, "broadcast: " + value + " foreground: " + foreground +
" with key: " + key);
Application application = AppUtils.getApp();
if (application == null) {
logger.log(Level.WARNING, "application is null, you can try setContext() when config");
return;
}
Intent intent = new Intent(IpcConst.ACTION);
if (foreground && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
}
if (onlyInApp) {
intent.setPackage(application.getPackageName());
}
intent.putExtra(IpcConst.KEY, key);
boolean handle = ProcessorManager.getManager().writeTo(intent, value);
try {
if (handle) {
application.sendBroadcast(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@MainThread
private void observeInternal(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerWrapper.preventNextEvent = liveData.getVersion() > ExternalLiveData.START_VERSION;
liveData.observe(owner, observerWrapper);
logger.log(Level.INFO, "observe observer: " + observerWrapper + "(" + observer + ")"
+ " on owner: " + owner + " with key: " + key);
}
@MainThread
private void observeStickyInternal(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
liveData.observe(owner, observerWrapper);
logger.log(Level.INFO, "observe sticky observer: " + observerWrapper + "(" + observer + ")"
+ " on owner: " + owner + " with key: " + key);
}
@MainThread
private void observeForeverInternal(@NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerWrapper.preventNextEvent = liveData.getVersion() > ExternalLiveData.START_VERSION;
observerMap.put(observer, observerWrapper);
liveData.observeForever(observerWrapper);
logger.log(Level.INFO, "observe forever observer: " + observerWrapper + "(" + observer + ")"
+ " with key: " + key);
}
@MainThread
private void observeStickyForeverInternal(@NonNull Observer<T> observer) {
ObserverWrapper<T> observerWrapper = new ObserverWrapper<>(observer);
observerMap.put(observer, observerWrapper);
liveData.observeForever(observerWrapper);
logger.log(Level.INFO, "observe sticky forever observer: " + observerWrapper + "(" + observer + ")"
+ " with key: " + key);
}
@MainThread
private void removeObserverInternal(@NonNull Observer<T> observer) {
Observer<T> realObserver;
if (observerMap.containsKey(observer)) {
realObserver = observerMap.remove(observer);
} else {
realObserver = observer;
}
liveData.removeObserver(realObserver);
}
private class LifecycleLiveData<T> extends ExternalLiveData<T> {
private final String key;
public LifecycleLiveData(String key) {
this.key = key;
}
@Override
protected Lifecycle.State observerActiveLevel() {
return lifecycleObserverAlwaysActive() ? Lifecycle.State.CREATED : Lifecycle.State.STARTED;
}
@Override
public void removeObserver(@NonNull Observer<T> observer) {
super.removeObserver(observer);
if (autoClear() && !liveData.hasObservers()) {
LiveEventBusCore.get().bus.remove(key);
}
logger.log(Level.INFO, "observer removed: " + observer);
}
private boolean lifecycleObserverAlwaysActive() {
if (observableConfigs.containsKey(key)) {
ObservableConfig config = observableConfigs.get(key);
if (config.lifecycleObserverAlwaysActive != null) {
return config.lifecycleObserverAlwaysActive;
}
}
return lifecycleObserverAlwaysActive;
}
private boolean autoClear() {
if (observableConfigs.containsKey(key)) {
ObservableConfig config = observableConfigs.get(key);
if (config.autoClear != null) {
return config.autoClear;
}
}
return autoClear;
}
}
private class PostValueTask implements Runnable {
private Object newValue;
public PostValueTask(@NonNull Object newValue) {
this.newValue = newValue;
}
@Override
public void run() {
postInternal((T) newValue);
}
}
private class PostLifeValueTask implements Runnable {
private Object newValue;
private LifecycleOwner owner;
public PostLifeValueTask(@NonNull Object newValue, @Nullable LifecycleOwner owner) {
this.newValue = newValue;
this.owner = owner;
}
@Override
public void run() {
if (owner != null) {
if (owner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
postInternal((T) newValue);
}
}
}
}
}
private class ObserverWrapper<T> implements Observer<T> {
@NonNull
private final Observer<T> observer;
private boolean preventNextEvent = false;
ObserverWrapper(@NonNull Observer<T> observer) {
this.observer = observer;
}
@Override
public void onChanged(@Nullable T t) {
if (preventNextEvent) {
preventNextEvent = false;
return;
}
logger.log(Level.INFO, "message received: " + t);
try {
observer.onChanged(t);
} catch (ClassCastException e) {
logger.log(Level.WARNING, "class cast error on message received: " + t, e);
} catch (Exception e) {
logger.log(Level.WARNING, "error on message received: " + t, e);
}
}
}
class InnerConsole {
String getConsoleInfo() {
StringBuilder sb = new StringBuilder();
sb.append("*********Base info*********").append("\n");
sb.append(getBaseInfo());
sb.append("*********Event info*********").append("\n");
sb.append(getBusInfo());
return sb.toString();
}
String getBaseInfo() {
StringBuilder sb = new StringBuilder();
sb.append("lifecycleObserverAlwaysActive: ").append(lifecycleObserverAlwaysActive).append("\n")
.append("autoClear: ").append(autoClear).append("\n")
.append("logger enable: ").append(logger.isEnable()).append("\n")
.append("logger: ").append(logger.getLogger()).append("\n")
.append("Receiver register: ").append(isRegisterReceiver).append("\n")
.append("Application: ").append(AppUtils.getApp()).append("\n");
return sb.toString();
}
String getBusInfo() {
StringBuilder sb = new StringBuilder();
for (String key : bus.keySet()) {
sb.append("Event name: " + key).append("\n");
ExternalLiveData liveData = bus.get(key).liveData;
sb.append("\tversion: " + liveData.getVersion()).append("\n");
sb.append("\thasActiveObservers: " + liveData.hasActiveObservers()).append("\n");
sb.append("\thasObservers: " + liveData.hasObservers()).append("\n");
sb.append("\tActiveCount: " + getActiveCount(liveData)).append("\n");
sb.append("\tObserverCount: " + getObserverCount(liveData)).append("\n");
sb.append("\tObservers: ").append("\n");
sb.append("\t\t" + getObserverInfo(liveData)).append("\n");
}
return sb.toString();
}
private int getActiveCount(LiveData liveData) {
try {
Field field = LiveData.class.getDeclaredField("mActiveCount");
field.setAccessible(true);
return (int) field.get(liveData);
} catch (Exception e) {
return -1;
}
}
private int getObserverCount(LiveData liveData) {
try {
Field field = LiveData.class.getDeclaredField("mObservers");
field.setAccessible(true);
Object mObservers = field.get(liveData);
Class<?> classOfSafeIterableMap = mObservers.getClass();
Method size = classOfSafeIterableMap.getDeclaredMethod("size");
size.setAccessible(true);
return (int) size.invoke(mObservers);
} catch (Exception e) {
return -1;
}
}
private String getObserverInfo(LiveData liveData) {
try {
Field field = LiveData.class.getDeclaredField("mObservers");
field.setAccessible(true);
Object mObservers = field.get(liveData);
return mObservers.toString();
} catch (Exception e) {
return "";
}
}
}
}
package com.sobot.widget.livedatabus.core;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.Observer;
import android.support.annotation.NonNull;
public interface Observable<T> {
/**
* 进程内发送消息
*
* @param value 发送的消息
*/
void post(T value);
/**
* App内发送消息,跨进程使用
*
* @param value 发送的消息
*/
void postAcrossProcess(T value);
/**
* App之间发送消息
*
* @param value 发送的消息
*/
void postAcrossApp(T value);
/**
* 进程内发送消息,延迟发送
*
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
void postDelay(T value, long delay);
/**
* 进程内发送消息,延迟发送,带生命周期
* 如果延时发送消息的时候sender处于非激活状态,消息取消发送
*
* @param sender 消息发送者
* @param value 发送的消息
* @param delay 延迟毫秒数
*/
void postDelay(LifecycleOwner sender, T value, long delay);
/**
* 进程内发送消息
* 强制接收到消息的顺序和发送顺序一致
*
* @param value 发送的消息
*/
void postOrderly(T value);
/**
* 以广播的形式发送一个消息
* 需要跨进程、跨APP发送消息的时候调用该方法
* 可使用postAcrossProcess or postAcrossApp代替
*
* @param value 发送的消息
*/
@Deprecated
void broadcast(T value);
/**
* 以广播的形式发送一个消息
* 需要跨进程、跨APP发送消息的时候调用该方法
*
* @param value 发送的消息
* @param foreground true:前台广播、false:后台广播
* @param onlyInApp true:只在APP内有效、false:全局有效
*/
void broadcast(T value, boolean foreground, boolean onlyInApp);
/**
* 注册一个Observer,生命周期感知,自动取消订阅
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer);
/**
* 注册一个Observer,生命周期感知,自动取消订阅
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param owner LifecycleOwner
* @param observer 观察者
*/
void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer);
/**
* 注册一个Observer,需手动解除绑定
*
* @param observer 观察者
*/
void observeForever(@NonNull Observer<T> observer);
/**
* 注册一个Observer,需手动解除绑定
* 如果之前有消息发送,可以在注册时收到消息(消息同步)
*
* @param observer 观察者
*/
void observeStickyForever(@NonNull Observer<T> observer);
/**
* 通过observeForever或observeStickyForever注册的,需要调用该方法取消订阅
*
* @param observer 观察者
*/
void removeObserver(@NonNull Observer<T> observer);
}
package com.sobot.widget.livedatabus.core;
public class ObservableConfig {
Boolean lifecycleObserverAlwaysActive = null;
Boolean autoClear = null;
/**
* lifecycleObserverAlwaysActive
* set if then observer can always receive message
* true: observer can always receive message
* false: observer can only receive message when resumed
*
* @param active boolean
* @return ObservableConfig
*/
public ObservableConfig lifecycleObserverAlwaysActive(boolean active) {
lifecycleObserverAlwaysActive = active;
return this;
}
/**
* @param clear boolean
* @return true: clear livedata when no observer observe it
* false: not clear livedata unless app was killed
*/
public ObservableConfig autoClear(boolean clear) {
autoClear = clear;
return this;
}
}
package com.sobot.widget.livedatabus.ipc.annotation;
import com.sobot.widget.livedatabus.ipc.core.Processor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface IpcConfig {
Class<? extends Processor> processor();
}
package com.sobot.widget.livedatabus.ipc.consts;
public class IpcConst {
public static final String ACTION = "intent.action.ACTION_LEB_IPC";
public static final String KEY = "leb_ipc_key";
public static final String KEY_VALUE = "leb_ipc_value";
public static final String KEY_PROCESSOR_NAME = "leb_ipc_processor_name";
public static final String KEY_BUNDLE = "leb_ipc_bundle";
public static final String KEY_CLASS_NAME = "leb_ipc_class_name";
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class BooleanProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Boolean)) {
return false;
}
bundle.putBoolean(IpcConst.KEY_VALUE, (boolean) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getBoolean(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class DoubleProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Double)) {
return false;
}
bundle.putDouble(IpcConst.KEY_VALUE, (Double) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getDouble(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class FloatProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Float)) {
return false;
}
bundle.putFloat(IpcConst.KEY_VALUE, (float) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getFloat(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class IntProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Integer)) {
return false;
}
bundle.putInt(IpcConst.KEY_VALUE, (int) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getInt(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class LongProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Long)) {
return false;
}
bundle.putLong(IpcConst.KEY_VALUE, (long) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getLong(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import android.os.Parcelable;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class ParcelableProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Parcelable)) {
return false;
}
bundle.putParcelable(IpcConst.KEY_VALUE, (Parcelable) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getParcelable(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
public interface Processor {
boolean writeToBundle(Bundle bundle, Object value) throws Exception;
Object createFromBundle(Bundle bundle) throws Exception;
}
package com.sobot.widget.livedatabus.ipc.core;
import android.content.Intent;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.annotation.IpcConfig;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class ProcessorManager {
private static class SingletonHolder {
private static final ProcessorManager INSTANCE = new ProcessorManager();
}
public static ProcessorManager getManager() {
return SingletonHolder.INSTANCE;
}
private final List<Processor> baseProcessors;
private final Map<String, Processor> processorMap;
{
baseProcessors = new LinkedList<>(Arrays.asList(
new StringProcessor(),
new IntProcessor(),
new BooleanProcessor(),
new DoubleProcessor(),
new FloatProcessor(),
new LongProcessor(),
new SerializableProcessor(),
new ParcelableProcessor()));
processorMap = new HashMap<>();
for (Processor processor : baseProcessors) {
processorMap.put(processor.getClass().getName(), processor);
}
}
private ProcessorManager() {
}
public boolean writeTo(Intent intent, Object value) {
if (intent == null || value == null) {
return false;
}
Bundle bundle = new Bundle();
boolean processed = false;
//用指定的processor处理
IpcConfig config = value.getClass().getAnnotation(IpcConfig.class);
if (config != null) {
Class<? extends Processor> processorType = config.processor();
String processorTypeName = processorType.getName();
if (!processorMap.containsKey(processorTypeName)) {
try {
processorMap.put(processorTypeName, processorType.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
Processor processor = processorMap.get(processorTypeName);
if (processor != null) {
try {
boolean handle = processor.writeToBundle(bundle, value);
if (handle) {
intent.putExtra(IpcConst.KEY_PROCESSOR_NAME, processor.getClass().getName());
intent.putExtra(IpcConst.KEY_BUNDLE, bundle);
processed = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (processed) {
return true;
}
}
//用默认的processor处理
for (Processor processor : baseProcessors) {
try {
boolean handle = processor.writeToBundle(bundle, value);
if (handle) {
intent.putExtra(IpcConst.KEY_PROCESSOR_NAME, processor.getClass().getName());
intent.putExtra(IpcConst.KEY_BUNDLE, bundle);
processed = true;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return processed;
}
public Object createFrom(Intent intent) {
if (intent == null) {
return null;
}
String processorName = intent.getStringExtra(IpcConst.KEY_PROCESSOR_NAME);
Bundle bundle = intent.getBundleExtra(IpcConst.KEY_BUNDLE);
if (processorName == null || processorName.length() == 0 || bundle == null) {
return null;
}
if (!processorMap.containsKey(processorName)) {
try {
processorMap.put(processorName, (Processor) Class.forName(processorName).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
Processor processor = processorMap.get(processorName);
if (processor == null) {
return null;
}
try {
return processor.createFromBundle(bundle);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import java.io.Serializable;
public class SerializableProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof Serializable)) {
return false;
}
bundle.putSerializable(IpcConst.KEY_VALUE, (Serializable) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getSerializable(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.core;
import android.os.Bundle;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
public class StringProcessor implements Processor {
@Override
public boolean writeToBundle(Bundle bundle, Object value) {
if (!(value instanceof String)) {
return false;
}
bundle.putString(IpcConst.KEY_VALUE, (String) value);
return true;
}
@Override
public Object createFromBundle(Bundle bundle) {
return bundle.getString(IpcConst.KEY_VALUE);
}
}
package com.sobot.widget.livedatabus.ipc.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.sobot.widget.livedatabus.SobotLiveEventBus;
import com.sobot.widget.livedatabus.ipc.consts.IpcConst;
import com.sobot.widget.livedatabus.ipc.core.ProcessorManager;
public class LebIpcReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (IpcConst.ACTION.equals(intent.getAction())) {
try {
String key = intent.getStringExtra(IpcConst.KEY);
Object value = ProcessorManager.getManager().createFrom(intent);
if (key != null && value != null) {
SobotLiveEventBus.get(key).post(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package com.sobot.widget.livedatabus.logger;
import android.util.Log;
import java.util.logging.Level;
public class DefaultLogger implements Logger {
private static final String TAG = "[LiveEventBus]";
@Override
public void log(Level level, String msg) {
if (level == Level.SEVERE) {
Log.e(TAG, msg);
} else if (level == Level.WARNING) {
Log.w(TAG, msg);
} else if (level == Level.INFO) {
Log.i(TAG, msg);
} else if (level == Level.CONFIG) {
Log.d(TAG, msg);
} else if (level != Level.OFF) {
Log.v(TAG, msg);
}
}
@Override
public void log(Level level, String msg, Throwable th) {
if (level == Level.SEVERE) {
Log.e(TAG, msg, th);
} else if (level == Level.WARNING) {
Log.w(TAG, msg, th);
} else if (level == Level.INFO) {
Log.i(TAG, msg, th);
} else if (level == Level.CONFIG) {
Log.d(TAG, msg, th);
} else if (level != Level.OFF) {
Log.v(TAG, msg, th);
}
}
}
package com.sobot.widget.livedatabus.logger;
import java.util.logging.Level;
public interface Logger {
void log(Level level, String msg);
void log(Level level, String msg, Throwable th);
}
package com.sobot.widget.livedatabus.logger;
import java.util.logging.Level;
public class LoggerManager implements Logger {
private Logger logger;
private boolean enable = true;
public LoggerManager(Logger logger) {
this.logger = logger;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public Logger getLogger() {
return logger;
}
public void setLogger(Logger logger) {
this.logger = logger;
}
@Override
public void log(Level level, String msg) {
if (enable) {
logger.log(level, msg);
}
}
@Override
public void log(Level level, String msg, Throwable th) {
if (enable) {
logger.log(level, msg, th);
}
}
}
package com.sobot.widget.livedatabus.utils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.FileProvider;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* from Github: https://github.com/Blankj/AndroidUtilCode
*/
public final class AppUtils {
private static final String PERMISSION_ACTIVITY_CLASS_NAME =
"com.blankj.utilcode.util.PermissionUtils$PermissionActivity";
private static final ActivityLifecycleImpl ACTIVITY_LIFECYCLE = new ActivityLifecycleImpl();
@SuppressLint("StaticFieldLeak")
private static Application sApplication;
private AppUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param context context
*/
public static void init(final Context context) {
if (context == null) {
init(getApplicationByReflect());
return;
}
init((Application) context.getApplicationContext());
}
/**
* Init utils.
* <p>Init it in the class of Application.</p>
*
* @param app application
*/
public static void init(final Application app) {
if (sApplication == null) {
if (app == null) {
sApplication = getApplicationByReflect();
} else {
sApplication = app;
}
sApplication.registerActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
} else {
if (app != null && app.getClass() != sApplication.getClass()) {
sApplication.unregisterActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
ACTIVITY_LIFECYCLE.mActivityList.clear();
sApplication = app;
sApplication.registerActivityLifecycleCallbacks(ACTIVITY_LIFECYCLE);
}
}
}
/**
* Return the context of Application object.
*
* @return the context of Application object
*/
public static Application getApp() {
if (sApplication != null) return sApplication;
Application app = getApplicationByReflect();
init(app);
return app;
}
private static Application getApplicationByReflect() {
try {
@SuppressLint("PrivateApi")
Class<?> activityThread = Class.forName("android.app.ActivityThread");
Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
Object app = activityThread.getMethod("getApplication").invoke(thread);
if (app == null) {
throw new NullPointerException("u should init first");
}
return (Application) app;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
throw new NullPointerException("u should init first");
}
static ActivityLifecycleImpl getActivityLifecycle() {
return ACTIVITY_LIFECYCLE;
}
static LinkedList<Activity> getActivityList() {
return ACTIVITY_LIFECYCLE.mActivityList;
}
static Context getTopActivityOrApp() {
if (isAppForeground()) {
Activity topActivity = ACTIVITY_LIFECYCLE.getTopActivity();
return topActivity == null ? AppUtils.getApp() : topActivity;
} else {
return AppUtils.getApp();
}
}
static boolean isAppForeground() {
ActivityManager am = (ActivityManager) AppUtils.getApp().getSystemService(Context.ACTIVITY_SERVICE);
if (am == null) return false;
List<ActivityManager.RunningAppProcessInfo> info = am.getRunningAppProcesses();
if (info == null || info.size() == 0) return false;
for (ActivityManager.RunningAppProcessInfo aInfo : info) {
if (aInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return aInfo.processName.equals(AppUtils.getApp().getPackageName());
}
}
return false;
}
static class ActivityLifecycleImpl implements ActivityLifecycleCallbacks {
final LinkedList<Activity> mActivityList = new LinkedList<>();
final Map<Object, OnAppStatusChangedListener> mStatusListenerMap = new HashMap<>();
final Map<Activity, Set<OnActivityDestroyedListener>> mDestroyedListenerMap = new HashMap<>();
private int mForegroundCount = 0;
private int mConfigCount = 0;
private boolean mIsBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
setTopActivity(activity);
}
@Override
public void onActivityStarted(Activity activity) {
if (!mIsBackground) {
setTopActivity(activity);
}
if (mConfigCount < 0) {
++mConfigCount;
} else {
++mForegroundCount;
}
}
@Override
public void onActivityResumed(Activity activity) {
setTopActivity(activity);
if (mIsBackground) {
mIsBackground = false;
postStatus(true);
}
}
@Override
public void onActivityPaused(Activity activity) {/**/
}
@Override
public void onActivityStopped(Activity activity) {
if (activity.isChangingConfigurations()) {
--mConfigCount;
} else {
--mForegroundCount;
if (mForegroundCount <= 0) {
mIsBackground = true;
postStatus(false);
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {/**/}
@Override
public void onActivityDestroyed(Activity activity) {
mActivityList.remove(activity);
consumeOnActivityDestroyedListener(activity);
fixSoftInputLeaks(activity);
}
Activity getTopActivity() {
if (!mActivityList.isEmpty()) {
final Activity topActivity = mActivityList.getLast();
if (topActivity != null) {
return topActivity;
}
}
Activity topActivityByReflect = getTopActivityByReflect();
if (topActivityByReflect != null) {
setTopActivity(topActivityByReflect);
}
return topActivityByReflect;
}
void addOnAppStatusChangedListener(final Object object,
final OnAppStatusChangedListener listener) {
mStatusListenerMap.put(object, listener);
}
void removeOnAppStatusChangedListener(final Object object) {
mStatusListenerMap.remove(object);
}
void removeOnActivityDestroyedListener(final Activity activity) {
if (activity == null) return;
mDestroyedListenerMap.remove(activity);
}
void addOnActivityDestroyedListener(final Activity activity,
final OnActivityDestroyedListener listener) {
if (activity == null || listener == null) return;
Set<OnActivityDestroyedListener> listeners;
if (!mDestroyedListenerMap.containsKey(activity)) {
listeners = new HashSet<>();
mDestroyedListenerMap.put(activity, listeners);
} else {
listeners = mDestroyedListenerMap.get(activity);
if (listeners.contains(listener)) return;
}
listeners.add(listener);
}
private void postStatus(final boolean isForeground) {
if (mStatusListenerMap.isEmpty()) return;
for (OnAppStatusChangedListener onAppStatusChangedListener : mStatusListenerMap.values()) {
if (onAppStatusChangedListener == null) return;
if (isForeground) {
onAppStatusChangedListener.onForeground();
} else {
onAppStatusChangedListener.onBackground();
}
}
}
private void setTopActivity(final Activity activity) {
if (PERMISSION_ACTIVITY_CLASS_NAME.equals(activity.getClass().getName())) return;
if (mActivityList.contains(activity)) {
if (!mActivityList.getLast().equals(activity)) {
mActivityList.remove(activity);
mActivityList.addLast(activity);
}
} else {
mActivityList.addLast(activity);
}
}
private void consumeOnActivityDestroyedListener(Activity activity) {
Iterator<Map.Entry<Activity, Set<OnActivityDestroyedListener>>> iterator
= mDestroyedListenerMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Activity, Set<OnActivityDestroyedListener>> entry = iterator.next();
if (entry.getKey() == activity) {
Set<OnActivityDestroyedListener> value = entry.getValue();
for (OnActivityDestroyedListener listener : value) {
listener.onActivityDestroyed(activity);
}
iterator.remove();
}
}
}
private Activity getTopActivityByReflect() {
try {
@SuppressLint("PrivateApi")
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Object currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field mActivityListField = activityThreadClass.getDeclaredField("mActivityList");
mActivityListField.setAccessible(true);
Map activities = (Map) mActivityListField.get(currentActivityThreadMethod);
if (activities == null) return null;
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
return (Activity) activityField.get(activityRecord);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
private static void fixSoftInputLeaks(final Activity activity) {
if (activity == null) return;
InputMethodManager imm =
(InputMethodManager) AppUtils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
String[] leakViews = new String[]{"mLastSrvView", "mCurRootView", "mServedView", "mNextServedView"};
for (String leakView : leakViews) {
try {
Field leakViewField = InputMethodManager.class.getDeclaredField(leakView);
if (leakViewField == null) continue;
if (!leakViewField.isAccessible()) {
leakViewField.setAccessible(true);
}
Object obj = leakViewField.get(imm);
if (!(obj instanceof View)) continue;
View view = (View) obj;
if (view.getRootView() == activity.getWindow().getDecorView().getRootView()) {
leakViewField.set(imm, null);
}
} catch (Throwable ignore) { /**/ }
}
}
}
public static final class FileProvider4UtilCode extends FileProvider {
@Override
public boolean onCreate() {
AppUtils.init(getContext());
return true;
}
}
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
public interface OnAppStatusChangedListener {
void onForeground();
void onBackground();
}
public interface OnActivityDestroyedListener {
void onActivityDestroyed(Activity activity);
}
}
package com.sobot.widget.livedatabus.utils;
import android.os.Looper;
public final class ThreadUtils {
public static boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment