前言
什么是ARouter?如果你想知道什么是ARouter的話,現在就帶你研究... 什么是ARouter ...
開玩耍... 今天不對ARouter的使用做過多講解,如果有對ARouter不了解的童鞋可以移步ARouter 官方學習。今天主要是基于ARouter做一些擴展,來波不是騷操作的騷操作~
如何通過ARouter實現類Retrofit鏈式調用onActivityResult ?
我們都知道啟動另外一個Activity有倆種方式:
- 使用startActivity()
- 使用startActivityOnResult()
startActivityOnResult()
和startActivity()
區別在于startActivityOnResult
可以從B頁面回傳數據到A頁面。
傳統啟動方式:
startActivityForResult(new Intent(this,OtherActivity.class),REQUEST_CODE);
ARouter啟動方式:
ARouter.getInstance().build(String path)
.navigation(Context mContext, int requestCode);
回調:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
那么問題來了!
我想通過Arouter直接回調拿到onActivityResult返回的數據呢?
就像... 這樣
ARouter.getInstance().build(String path)
.navigation(Context mContext, int requestCode)
.setOnResultCallback(new OnResultCallback(){
@Override
public void onResponse(Object data){
}
});
分析:
我們想要實現類似如上的方式,正常的ARouter跳轉方法肯定是實現不了,我們需要暴露方法提供給他人使用,同時還需要拿到ARouter相關的方法對象。
通過ARouter文檔發現,想要提供服務暴露給其他人使用,ARouter提供了一個接口:IProvider
public interface IProvider {
/**
* Do your init work in this method, it well be call when processor has been load.
*
* @param context ctx
*/
void init(Context context);
}
嗯.. 這就好辦了,我們第一步需要實現的是在onActivityResult
方法中將返回的結果通過路由服務中的方法進行操作
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
SelectInfo selectInfo = (SelectInfo) data.getSerializableExtra("selectInfo");
Log.e("Rain",selectInfo.getName() + "--------onActivityResult----------");
XRouter.getRouter().getActivityManager().onActivityResult(this, requestCode, resultCode, data);
}
服務的實現類
@Route(path = IActivityManagerService.PATH)
public class ActivityManagerImpl implements IProvider, IActivityManagerService {
private Context mContext;
private List<OnActivityResultListener> mOnActivityResultListeners;
@Override
public void init(Context context) {
mContext = context;
}
@Override
public Context getContext() {
if (ActivityUtils.getTopActivity() == null)
return mContext;
else return ActivityUtils.getTopActivity();
}
@Override
public void addOnActivityResultListener(OnActivityResultListener listener) {
if(mOnActivityResultListeners == null){
mOnActivityResultListeners = new ArrayList<>();
}
if(!mOnActivityResultListeners.contains(listener)){
mOnActivityResultListeners.add(listener);
}
}
@Override
public void onActivityResult(Activity context, int requestCode, int resultCode, Intent data) {
if(mOnActivityResultListeners != null && !mOnActivityResultListeners.isEmpty()){
for(OnActivityResultListener listener : mOnActivityResultListeners){
listener.onActivityResult(context, requestCode, resultCode, data);
}
}
}
}
調用方式:
public IActivityManagerService getActivityManager() {
ActivityManagerImpl activityManagerImpl = (ActivityManagerImpl)ARouter.getInstance()
.build(IActivityManagerService.PATH)
.navigation();
return activityManagerImpl;
}
第二步我們需要做路由跳轉服務的實現 類似:
XRouter.getRouter()...startActivityForResult(new ResultCallback() {
@Override
public void onResponse(@NonNull Object data) {
}
});
Arouter調用build方法后返回一個PostCard,官方解釋A container that contains the roadmap.這是個路由信息的存儲器,里面包含頁面跳轉的所有信息。
那么我們跳轉時傳遞參數必須先拿到一個PostCard,通過PostCard可以傳遞我們目標頁面所需的數據
Postcard mPostcard = ARouter.getInstance().build(path);
通過new NavigatorBuilder(String path)
可以拿到NavigatorBuilder對象:
NavigatorBuilder navigator = new NavigatorBuilder(path);
路由跳轉時我們需要的參數大致有path路徑,requestCode以及傳遞的數據,如果使用靜態代理去實現的話,后期可能不太好維護,那么一個更好的解決辦法就是使用注解+動態代理,可以實現類Retrofit式使用,方便擴展維護。
創建注解類:
//方法注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Route {
/**
* 跳轉路徑
* @return
*/
String path();
/**
* 請求碼
* @return
*/
int requestCode() default -1;
}
//方法參數注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Extras {
}
使用:
public interface AppNavigator {
String _selectPage = "/select/contactActivity";
@Route(path = _selectPage)
ActivityNavigator<SelectInfo> toSelectContactPage(@Extras Bundle bundle);
}
這時我們可以通過反射拿到AppNavigator
對象。
這里其實使用的是動態代理,內部也是通過Java反射機制實現的,即已知的一個對象,然后在運行時動態調用其方法,這樣在調用前后作一些相應的處理。
try {
o = Proxy.newProxyInstance(navigator.getClassLoader(), new Class[]{navigator}, new InvocationHandler() {
LruCache<Method, NavigationMethod> mNavigatorMethods;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (mNavigatorMethods == null) {
mNavigatorMethods = new LruCache<>(5);
}
NavigationMethod navigationMethod = mNavigatorMethods.get(method);
if (navigationMethod == null) {
// create method's processer
navigationMethod = new NavigationMethod(method);
mNavigatorMethods.put(method, navigationMethod);
}
return navigationMethod.invoke(args);
}
});
}catch (Exception e){
Log.e("Rain",e.getMessage() + "-----------");
}
//CLassLoader loader:被代理對象的類加載器
//Class<?> interfaces:被代理類全部的接口
//InvocationHandler h:實現InvocationHandler接口的對象,在調用方式時會調用它的invoke方法。
調用Proxy的newProxyInstance方法可以生成代理對象 ,實現InvocationHandler接口的對象,在調用方式時會調用它的invoke方法,可以看到這個方法中調用了被代理對象的方法: method.invoke(),所以我們可以在這里加上我們的業務邏輯。
NavigationMethod.class:
public Object invoke(Object[] args) {
NavigatorBuilder builder = XRouter.getRouter().build(mRoute.path());
Navigator navigator = builder
.withRequestCode(mRoute.requestCode())
.navigator();
return navigator;
}
我們在ContactSelectInfoCallback中解析了返回的intent對象,并通過onResponse方法返回具體的數據對象。
public abstract class RouteCallback<T>{
public void onResponse(int requestCode, int resultCode, Intent data){
if(data != null){
try{
T parseData = parseData(requestCode, resultCode, data);
if(parseData != null){
onResponse(parseData);
}else{
onError(new RuntimeException("no data parsed"));
}
}catch(Exception e){
onError(new RuntimeException("an exception been catched when parsing data", e));
}
}else{
onCancel();
}
}
public abstract T parseData(int requestCode, int resultCode, @NonNull Intent data);
public abstract void onResponse(@NonNull T data);
public void onCancel(){}
public void onError(Throwable throwable){}
}
ok,基本工作完成
使用方式
1. 聲明Navigator接口
public interface AppNavigator {
String _selectPage = "/select/contactActivity";
//聲明返回類型為Navigator<T>, T為需要解析的回傳數據類型
@Route(path = _selectPage)
Navigator<SelectInfo> toSelectContactPage(@Extras Bundle ss);
}
2. 復寫onActivityResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
XRouter.getRouter().getActivityManager().onActivityResult(this, requestCode, resultCode, data);
}
3. 實現Callback,對回傳數據進行解析處理
public abstract class ContactSelectInfoCallback extends RouteCallback<SelectInfo> {
@Override
public SelectInfo parseData(int requestCode, int resultCode, @NonNull Intent data) {
return (SelectInfo)data.getSerializableExtra("selectInfo");
}
}
4. 發起路由
XRouter.getRouter()
.create(AppNavigator.class)
.toSelectContactPage(bundle)
.startActivityForResult(new ContactSelectInfoCallback() {
@Override
public void onResponse(@NonNull SelectInfo data) {
Log.e("Rain", data.getName() + "-----------onResponse--------");
}
});
輸出結果:
E: Rain--------onActivityResult----------
E: Rain-----------onResponse--------
完整代碼及解析使用移步github項目:XRouter