作者: Dawish_大D
: http://www.jianshu.com/u/40e1f22c2c53

(一)Android官方MVVM框架实现组件化之整体结构
(二)Android官方MVVM框架实现组件化之ARouter串联各模块

目前的项目结构图置顶:Demo的Github地址: https://github.com/Dawish/GoogleArchitectureDemo

(二)Android官方MVVM框架实现组件化之ARouter串联各模块_第1张图片 0-演示项目MVVM组件化架构图

ARouter路由器简直是MVVM组件化的一个天赐之物,非常适合在组件化中使用,可以很方便滴获取Fragment、跳转Activity、拦截跳转、启动服务等等。

ARouter官方地址:https://github.com/alibaba/ARouter

上面结构图中,module_girlsmodule_newslib_commoin 中都可能存在Activity,Fragment或者Service这些可以被ARouter支持的组件,其实ARouter的跳转是根据我们指定的路径去匹配的,只要路径是匹配的就可以跳转、获取或者是启动,最方便的是还支持参数携带,本文章只是讲一下在MVVMARouter最方便的使用场景,更多使用详情还请参考官方说明和官方Demo,官方说得很清楚了。


一、组件化中ARouter使用配置注意事项

本演示项目中AppModulelib一个有七个,如果是你每一个都用到了ARouter的功能,那么就需要在每一个模块的build.gradle中添加配置,记住是每一个。

android {    defaultConfig {    ...    javaCompileOptions {        annotationProcessorOptions {        arguments = [ moduleName : project.getName() ]        }    }    }}dependencies {    // 替换成最新版本, 需要注意的是api    // 要与compiler匹配使用,均使用最新版可以保证兼容    compile 'com.alibaba:arouter-api:x.x.x'    annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'    ...}

如果你的模块需要打包成apk或者是aar之类的,并且你开取了代码混淆,那么需要在每一个模块的proguard-rules.pro文件中添加代码keep

-keep public class com.alibaba.android.arouter.routes.**{*;}-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现-keep class * implements com.alibaba.android.arouter.facade.template.IProvider

二、Activity的跳转和拦截

首先我们需要在公共库 lib_common中添加一个类来存放ARouter的跳转获取使用的path

package google.architecture.common.base;/** * Created by danxx on 2017/11/27. * 路由path * * Aty : Activity * Fgt : Fragment * *//** * Created by danxx on 2017/11/27. * 路由path * * Aty : Activity * Fgt : Fragment * */public class ARouterPath {    /**妹子列表Activity*/    public static final String GirlsListAty = "/girls/aty/list";    /**妹子列表动态Activity*/    public static final String DynaGirlsListAty = "/girls/dynaty/list";    /**新闻列表Activity*/    public static final String NewsListAty = "/news/aty/list";    /**妹子列表Fragment*/    public static final String GirlsListFgt = "/girls/aty/fgt/list";    /**新闻列表Fragment*/    public static final String NewsListFgt = "/news/fgt/list";    /**关于Fragment*/    public static final String AboutFgt = "/about/fgt/fragment";}

需要被跳转的Activity增加Router注解,就是声明已下自己的path路径:

@Route(path = ARouterPath.GirlsListAty)public class ActivityGirls extends BaseActivity {    GirlsAdapter            girlsAdapter;    ActivityGirlsBinding    activityGirlsBinding;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setTitle("Module_ActivityGirls");        getSupportActionBar().setDisplayHomeAsUpEnabled(true);        activityGirlsBinding = DataBindingUtil.setContentView(ActivityGirls.this,R.layout.activity_girls);        GirlsViewModel girlsViewModel = new GirlsViewModel(ActivityGirls.this.getApplication());        girlsAdapter = new GirlsAdapter(girlItemClickCallback);        activityGirlsBinding.setRecyclerAdapter(girlsAdapter);        subscribeToModel(girlsViewModel);    }    GirlItemClickCallback   girlItemClickCallback = new GirlItemClickCallback() {        @Override        public void onClick(GirlsData.ResultsBean fuliItem) {            Toast.makeText(ActivityGirls.this, fuliItem.getDesc(), Toast.LENGTH_SHORT).show();        }    };    /**     * 订阅数据变化来刷新UI     * @param model     */    private void subscribeToModel(final GirlsViewModel model){        //观察数据变化来刷新UI        model.getLiveObservableData().observe(this, new Observer() {            @Override            public void onChanged(@Nullable GirlsData girlsData) {                Log.i("danxx", "subscribeToModel onChanged onChanged");                model.setUiObservableData(girlsData);                girlsAdapter.setGirlsList(girlsData.getResults());            }        });    }    @Override    protected void onResume() {        super.onResume();    }}

有兴趣的可以看一下ActivityGirls 的布局文件:

<?xml version="1.0" encoding="utf-8"?>                                                                                                

ARouter的拦截很简单的,写一个类实现IInterceptor接口,用Interceptor注解写上拦截器的等级和名字就可以了,不需要额外的去注册拦截器,在ARouter执行跳转时会先执行拦截器。关于java AOP注解的使用请看我之前的文章《大话AOP与Android的爱恨情仇》

/** * Created by danxx on 2017/11/27. * * 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查 * 拦截器会在跳转之前执行,多个拦截器会按优先级顺序依次执行 * * priority就是优先级 可以设置多个级别的拦截器都活一次执行 * 创建一个实现IInterceptor接口的类就是一个拦截器,不用做额外的配置了 */@Interceptor(priority = 8, name = "测试用拦截器")public class RouterInterceptor implements IInterceptor {    @Override    public void process(Postcard postcard, InterceptorCallback callback) {        if(postcard.getPath().contains(ARouterPath.GirlsListAty)){            Log.d("danxx", "拦截到向ActivityGirls跳转");            //自定义处理        }else {            Log.d("danxx", "非拦截跳转执行path: "+postcard.getPath());        }        callback.onContinue(postcard);  // 处理完成,交还控制权        // callback.onInterrupt(new RuntimeException("我觉得有点异常"));   // 觉得有问题,中断路由流程        // 以上两种至少需要调用其中一种,否则不会继续路由    }    @Override    public void init(Context context) {            // 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次        Log.d("danxx", "RouterInterceptor init");    }}

跳转的时候就厉害了哦,可以支持很多的参数携带,Activity的跳转还可以自动以转场动画:

   private ItemClick itemClick = new ItemClick() {        @Override        public void onClick(int id) {            switch (id){                case R.id.toGirls:                    Log.i("danxx", "onClick toGirls");                    //跳转到GirlsActivity                    ARouter.getInstance()                            .build(ARouterPath.GirlsListAty)                            /**可以针对性跳转跳转动画*/                            .withTransition(R.anim.activity_up_in, R.anim.activity_up_out)                            .navigation(ActivityMain.this);                    break;                case R.id.toNews:                    Log.i("danxx", "onClick toNews");                    //跳转到NewsActivity                    ARouter.getInstance()                            .build(ARouterPath.NewsListAty)                            /**可以针对性跳转跳转动画*/                            .withTransition(R.anim.activity_up_in, R.anim.activity_up_out)                             /**设置跳转回到*/                            .navigation(ActivityMain.this, 2, new NavigationCallback() {                                @Override                                public void onFound(Postcard postcard) {                                    Log.i("danxx", "ARouter onFound 找到跳转匹配路径");                                }                                @Override                                public void onLost(Postcard postcard) {                                    Log.i("danxx", "ARouter onLost 没有匹配到跳转路径");                                }                                @Override                                public void onArrival(Postcard postcard) {                                    Log.i("danxx", "ARouter onArrival 成功跳转");                                }                                @Override                                public void onInterrupt(Postcard postcard) {                                    Log.i("danxx", "ARouter onInterrupt 跳转被中断");                                }                            });                    break;                case R.id.toDynamic:                    Log.i("danxx", "onClick toNews");                    //跳转到ActivityDynamicGirls (模拟动态url)                    ARouter.getInstance()                            .build(ARouterPath.DynaGirlsListAty)                            .withString("fullUrl", "http://gank.io/api/data/%E7%A6%8F%E5%88%A9/20/1")                            .withTransition(R.anim.activity_up_in, R.anim.activity_up_out)                             /**支持携带requestCode参数,跳转回调onActivityResult方法*/                            .navigation(ActivityMain.this, 3);                    break;            }        }    };

三、Fragment的获取

看一下需要被获取Fragment:

/** * @Desc FragmentGirls */@Route(path = ARouterPath.GirlsListFgt)public class FragmentGirls extends BaseFragment {    FragmentGirlsBinding girlsBinding;    GirlsAdapter            girlsAdapter;    private static final String ARG_PARAM1 = "param1";    private static final String ARG_PARAM2 = "param2";    private String mParam1;    private String mParam2;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (getArguments() != null) {            mParam1 = getArguments().getString(ARG_PARAM1);            mParam2 = getArguments().getString(ARG_PARAM2);        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        ARouter.getInstance().inject(FragmentGirls.this);        girlsBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_girls,container,false);        girlsAdapter = new GirlsAdapter(girlItemClickCallback);        girlsBinding.setRecyclerAdapter(girlsAdapter);        final GirlsViewModel girlsViewModel = new GirlsViewModel(getActivity().getApplication());        subscribeToModel(girlsViewModel);        return girlsBinding.getRoot();    }    GirlItemClickCallback   girlItemClickCallback = new GirlItemClickCallback() {        @Override        public void onClick(GirlsData.ResultsBean fuliItem) {            Toast.makeText(getContext(), fuliItem.getDesc(), Toast.LENGTH_SHORT).show();        }    };    /**     * 订阅数据变化来刷新UI     * @param model     */    private void subscribeToModel(final GirlsViewModel model){        //观察数据变化来刷新UI        model.getLiveObservableData().observe(FragmentGirls.this, new Observer() {            @Override            public void onChanged(@Nullable GirlsData girlsData) {                Log.i("danxx", "subscribeToModel onChanged onChanged");                model.setUiObservableData(girlsData);                girlsAdapter.setGirlsList(girlsData.getResults());            }        });    }}

获取Fragment的时候也很单纯:

      BaseFragment fragmentNews = (BaseFragment) ARouter.getInstance().build(ARouterPath.NewsListFgt).navigation();BaseFragment fragmentGirls = (BaseFragment) ARouter.getInstance().build( ARouterPath.GirlsListFgt).navigation();BaseFragment fragmentAbout = (BaseFragment) ARouter.getInstance().build( ARouterPath.AboutFgt ).navigation();

四、ARouter所谓的服务获取

一开始看到这个,我还以为是获取Android中Service,其实不是的,ARouter所谓的服务就是直接或者是间接实现ARouter提供的IProvider接口的类。

首先我们可以先写一个继承IProvider接口的接口,我们可以在自己的接口中增加自己想要的方法:

/** * Created by danxx on 2017/11/28. * *  ARouter所谓的服务就是直接或者是间接实现ARouter提供的IProvider接口的类 * */public interface TestService extends IProvider {    /**增加自己想要的方法*/    String sayHello(String name);}

实现这个接口:

/** * Created by danxx on 2017/11/28. * 实现了一个测试用的服务接口 */@Route(path = "/service/test", name = "测试服务")public class TestServiceImpl implements TestService {    @Override    public String sayHello(String name) {        Log.d("danxx", "TestServiceImpl sayHello : "+name);        return "TestServiceImpl TestServiceImpl TestServiceImpl";    }    @Override    public void init(Context context) {        Log.d("danxx", "TestServiceImpl TestServiceImpl init");    }}

使用的时候可以有多种方式了:

服务声明:

    @Autowired(name = "/service/test")    TestService testService1;    TestService testService2;    TestService testService3;

服务使用:

        //注入才可以自动初始化Autowired注解声明的变量        ARouter.getInstance().inject(ActivityMain.this);        //注解的方法        testService1.sayHello("Autowired invoke 233");        //类寻找的方法        testService2 = ARouter.getInstance().navigation(TestService.class);        testService2.sayHello("navigation invoke 233");        //路径匹配的方式        testService3 = (TestService) ARouter.getInstance().build("/service/test").navigation();        testService3.sayHello("build invoke 233");

官方推荐注解的方式,比较靠谱一些。

MVVM中使用ARouter优点总结:

  1. 个模块之间更加低耦合,各模块之间不需要关注彼此,要埋头开发自己的功能就行了。

  2. Activity的跳转、Fragment的获取、ARouter所谓的Service 的获取,都变得很隐式,执行之前不知道对方具体是谁,只要对方注册了对应的path路径就可以了。

  3. 支持Activity的跳转的拦截,我测试似乎不支持Fragment的获取拦截,有些遗憾,在不满足情况的条件下模块可以对外屏蔽。

  4. 支持URL跳转,方便H5和原生混合开发。

...

五、无耻的预告

下一篇讲解DataBinding在MVVM中的使用,关于更多的ARouter请参考官方说明和官方Demo:

ARouter Github地址: https://github.com/alibaba/ARouter

示例工程Demo地址:https://github.com/Dawish/GoogleArchitectureDemo

更多相关文章

  1. Android非常好用的组件或者框架
  2. Android的四大组件之三--Activity(1)----->生命周期
  3. Android 6.0 新特性(官方文档翻译)
  4. Android Studio自动化快速实现Parcelable接口序列化
  5. Android官方使低版本系统(2.1)支持ActionBar的方法
  6. Android 接口定义语言AIdl
  7. Google SwipeRefreshLayout(Goolge官方下拉刷新控件)尝鲜

随机推荐

  1. android获取CPU参数(命令行方式)
  2. Android简单音乐播放实例
  3. Android SDK文档如何查找
  4. Android 获取扫码枪的扫描内容
  5. Android常见问题及讨论(41-45)
  6. android studio入坑及解决方案
  7. Android 重写DatePicker------只显示 年-
  8. Android O startForegroundService(前台服
  9. android文件上传到服务器
  10. Android使用httpPost向服务器发送请求的