美文网首页
基于ARouter实现startActivityForResul

基于ARouter实现startActivityForResul

作者: 老鱼的储物柜 | 来源:发表于2021-11-14 14:34 被阅读0次
    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<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

    相关文章

      网友评论

          本文标题:基于ARouter实现startActivityForResul

          本文链接:https://www.haomeiwen.com/subject/ecwnsltx.html