7

Android 彻底组件化—如何使用 Arouter

 3 years ago
source link: http://www.androidchina.net/8221.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Android 彻底组件化—如何使用 Arouter – Android开发中文站
你的位置:Android开发中文站 > Android开发 > 开发进阶 > Android 彻底组件化—如何使用 Arouter

得到Android组件化方案已经开源,参见Android组件化方案开源。方案的解读文章是一个小的系列,这是系列的第五篇文章:

1、Android彻底组件化方案实践

2、Android彻底组件化demo发布

3、Android彻底组件化-代码和资源隔离

4、Android彻底组件化—UI跳转升级改造

5、Android彻底组件化—如何使用Arouter

上篇文章讲到,DDComponent已经进行了UI跳转的升级改造,可以支持路由的自动注册和路由表的自动生成。但是很多使用组件化方案的同学都表示项目中已经接入ARouter来进行UI跳转,迁移成本比较高。因此我就专门写了这篇文章,讲解一下如何在组件中使用ARouter。

不论用DDComponent自带的方案还是ARouter,要做到组件之间自由并且可控的跳转,需要做到下面几点:

1、路由跳转需要支持传递基本类型和自定义类型(例如Object)

2、路由的跳转需要和组件的生命周期一致,即只有加载的组件才可以跳转,卸载后的组件是不可达的

3、最好生成路由表,组件对外提供的路由可以轻松查阅到

下面我们就从配置开始一步步的讲怎么使用ARouter

增加必要的配置

basiclib模块中增加以下依赖,basiclib是组件化框架中共用的依赖库:

compile 'com.alibaba:arouter-api:1.3.0'

在跳转的目标组件的build.gradle中,增加以下配置:

android {
    defaultConfig {
    ...
    javaCompileOptions {
        annotationProcessorOptions {
        arguments = [ moduleName : project.getName() ]
        }
    }
    }
}
dependencies {
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
    ...
}

在组件化框架中,我们的示例是从readercomponent跳转到sharecomponent,所以上述配置增加在sharecomponent下面的build.gradle中。

在目标页面增加相应的注解

我们以“分享图书” 页面为例

@Route(path = "/share/shareBook")
public class ShareActivity extends AppCompatActivity {

在进入这个页面,需要传入两个参数,一个是String类型的bookName,一个是自定义类型Author的author

@Autowired
String bookName;
@Autowired
Author author;

如何传递自定义类型

由于自定义类型Author需要跨组件传递,我们知道,DDComponent的核心之处就是在组件之间见了一堵墙,在编译期代码和资源都是完全隔离的,所以Author必须定义在share组件向外提供的服务中。所以我们在component中,定义Author类:

public class Author {
    private String name;
    private int age;
    private String county;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getCounty() {
        return county;
    }
    public void setCounty(String county) {
        this.county = county;
    }
}

现在就解决了Author的可见性问题,但是为了能在路由中传递,按照ARouter的要求,还需要自己实现SerializationService:

@Route(path = "/service/json")
public class JsonServiceImpl implements SerializationService {
    @Override
    public void init(Context context) {}
    @Override
    public <t> T json2Object(String text, Class<t> clazz) {
        return JSON.parseObject(text, clazz);
    }
    @Override
    public String object2Json(Object instance) {
        return JSON.toJSONString(instance);
    }
    @Override
    public <t> T parseObject(String input, Type clazz) {
        return JSON.parseObject(input, clazz);
    }
}

这里笔者就遇到了一个坑,本来我把这个类定义在readercomponent中,结果运行之后会报空指针异常。只有我把类移到sharecomponent之后,异常才消失。暂时没找到原因,但是定义在这里,加入要跳转到readercomponent怎么办呢?

在组件化框架demo中,发起跳转是readercomponent中的ReaderFragment中,demo中列出了两个示例:
普通跳转

private void goToShareActivityNormal() {
    Author author = new Author();
    author.setName("Margaret Mitchell");
    author.setCounty("USA");
    ARouter.getInstance().build("/share/shareBook")
            .withString("bookName", "Gone with the Wind")
            .withObject("author", author)
            .navigation();
}

以及startActivityForResult

private void goToShareActivityForResult() {
    Author author = new Author();
    author.setName("Margaret Mitchell");
    author.setCounty("USA");
    ARouter.getInstance().build("/share/shareMagazine")
            .withString("bookName", "Gone with the Wind")
            .withObject("author", author)
            .navigation(getActivity(), REQUEST_CODE);
}

控制生命周期

经过上面的操作,已经可以完成UI跳转了。但是如果运行demo就可以发现,此时即使卸载了分享组件,分享书的页面还是可以进入的,说明生命周期没有同步。在DDComponent自带的方案中是不存在这个问题的,因为跳转的逻辑已经与组件化生命周期绑定在一起。

这里就用到ARouter自带的拦截器功能,每个组件都需要定义一个拦截器,当组件卸载之后需要拦截住该组件的跳转入口。

下面是分享组件拦截器的示例代码:

@Interceptor(priority = 1, name = "分享组件拦截器")
public class ShareInterceptor implements IInterceptor {
    public static boolean isRegister;
    Context mContext;
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
        if (isRegister) {
            callback.onContinue(postcard);
        } else if ("/share/shareBook".equals(postcard.getPath())
                || "/share/shareMagazine".equals(postcard.getPath())) {
            MainLooper.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "分享组件已经卸载", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    @Override
    public void init(Context context) {
        mContext = context;
    }
}

这里通过一个isRegister开关来控制拦截器是否生效,为了保证生命周期一致性,在ShareApplike中增加赋值逻辑:

public class ShareApplike implements IApplicationLike {
    @Override
    public void onCreate() {
        ShareInterceptor.isRegister = true;
    }
    @Override
    public void onStop() {
        ShareInterceptor.isRegister = false;
    }
}

但是这里也遇到了两个小坑,不知道是否是ARouter使用不当:

(1)添加或者修改拦截器之后,必须卸载重装app才能生效,不论是clean还是rebuild都是不生效的

(2)拦截器中需要硬编码该组件的所有路由,例如/share/shareBook等,一旦路由发生了改变,一定要记得修改这个地方

路由表生成

这个ARouter暂时没有提供,DDComponent自带的方案增加了这个功能,当组件build生成之后,在根目录生成UIRouterTable文件夹,里面会列出每个组件向外提供的路由表以及具体参数

auto generated, do not change !!!! 

HOST : share

分享杂志页面
/shareMagazine
author:com.luojilab.componentservice.share.bean.Author
bookName:String

分享书籍页面
/shareBook
author:com.luojilab.componentservice.share.bean.Author
bookName:String

这点对于组件的协同开发是比较重要的,毕竟跳转之前翻阅别人的代码是件比较费事的工作

简单做一个总结:

(1)ARouter是一个优秀的路由跳转方案,DDComponent自带的方案也参考了很多其中的想法,功能很强大

(2)使用中需要与组件化方案兼容的地方主要是生命周期相关,在拦截器上增加部分逻辑就可以完成

(3)ARouter使用中还存在一些小的问题,可能是姿势不对,接入中走了不少弯路,有熟悉这块的朋友可以指出原因

(4)路由表没有自动生成,对外没有暴露有哪些路由协议和参数,对于组件之间协同开发不太友好

上面的代码已经发布DDComponent的master-arouter分支,欢迎大家使用,源码地址: https://github.com/luojilab/DDComponentForAndroid


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK