基于ARouter实现startActivityForResult的链式调用

Android

前言

什么是ARouter?如果你想知道什么是ARouter的话,现在就带你研究... 什么是ARouter ...

开玩耍... 今天不对ARouter的使用做过多讲解,如果有对ARouter不了解的童鞋可以移步ARouter 官方学习。今天主要是基于ARouter做一些扩展,来波不是骚操作的骚操作~

如何通过ARouter实现类Retrofit链式调用onActivityResult ?


我们都知道启动另外一个Activity有俩种方式:

  1. 使用startActivity()
  2. 使用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 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 toSelectContactPage(@Extras Bundle bundle);
}

这时我们可以通过反射拿到AppNavigator 对象。

这里其实使用的是动态代理,内部也是通过Java反射机制实现的,即已知的一个对象,然后在运行时动态调用其方法,这样在调用前后作一些相应的处理。

 try {
     o = Proxy.newProxyInstance(navigator.getClassLoader(), new Class[]{navigator}, new InvocationHandler() {
         LruCache 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{

    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为需要解析的回传数据类型
    @Route(path = _selectPage)
    Navigator 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 {
    @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

你可能感兴趣的:(基于ARouter实现startActivityForResult的链式调用)