新浦京81707con > 注册购买 > 安卓组件化应用的6,Android路由框架Router分析

原标题:安卓组件化应用的6,Android路由框架Router分析

浏览次数:146 时间:2020-03-15

始建拦权限截器:

@Route({"user", "http://example.com/user"})public class UserActivity extends Activity { ...}

2.ARouter的使用

1.增添框架的依附和安排

在挨门挨户模块的build.gradle中加多编写翻译参数和凭仗的框架

android {
    defaultConfig {
    ...
    javaCompileOptions {
        annotationProcessorOptions {
        arguments = [ moduleName : project.getName() ]
        }
    }
    }
}

dependencies {
    // 替换成最新版本, 需要注意的是api
    // 要与compiler匹配使用,均使用最新版可以保证兼容
    compile 'com.alibaba:arouter-api:1.2.2'
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.3'
    ...
}

// 旧版本gradle插件(< 2.2),可以使用apt插件,在根build.gradle中配置方法
apply plugin: 'com.neenbedankt.android-apt'

buildscript {
    repositories {
        jcenter()    
    }

    dependencies {
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}

2.增多评释

// 在支持路由的页面上添加注解(必选)
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
    ...
}

3.初始化SDK

if (isDebug()) {           // 这两行必须写在init之前,否则这些配置在init过程中将无效
    ARouter.openLog();     // 打印日志
    ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化

4.路由操作

// 1.普通跳转
ARouter.getInstance().build("/test/activity").navigation();

// 2.跳转并携带参数
ARouter.getInstance().build("/test/activity2").navigation();
// 3.跳转并携带请求码
ARouter.getInstance().build("/test/activity2").navigation(this, requestCode);

// 4.URI跳转 
/*这种使用URi的方式中,URi的Scheme 和 host不影响结果,可以随便设,关键的是path
*  - build(URI)会把URI解析为path,并把当前URI存入PostCard
*  - build(String)构造的PostCard不存储URI*/
Uri testUriMix = Uri.parse("xx://xxx/test/activity2");
ARouter.getInstance().build(testUriMix)
                        .withString("name", "老王")
                        .withInt("age", 18)
                        .withBoolean("boy", true)
                        .withLong("high", 180)
                        .withString("url", "https://a.b.c")
                        .withParcelable("pac", testParcelable)
                        .withObject("obj", testObj)
                        .navigation();

// 5.跳转包含回调 单次降级策略可以在这里使用
ARouter.getInstance().build("/test/activity2").navigation(Context mContext, int requestCode, NavigationCallback callback);

5.配置自定义类别化情势

上诉的代码中有withObject实行传参,没有概念系列化方式是心余力绌开展深入分析因而要求定义三个种类化格局,以下采纳法斯特Json举行体系化

// 如果需要传递自定义对象,需要实现 SerializationService,并使用@Route注解标注(方便用户自行选择序列化方式),例如:
@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);
    }
}

6.注脚拦截器(拦截跳转进程,面向切面编制程序卡塔尔国

// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
@Interceptor(priority = 8, name = "测试用拦截器")
public class TestInterceptor implements IInterceptor {
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
    ...
    callback.onContinue(postcard);  // 处理完成,交还控制权
    // callback.onInterrupt(new RuntimeException("我觉得有点异常"));      // 觉得有问题,中断路由流程

    // 以上两种至少需要调用其中一种,否则不会继续路由
    }

    @Override
    public void init(Context context) {
    // 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
    }
}

// 我们平常须求在对象页面中配置部分品质,举例说"是或不是需求登录"之类的
// 能够因而 Route 注脚中的 extras 属性实行扩充,这一个天性是一个int值,换句话说,单个int有4字节,相当于33人,能够布置31个按键
// 剩下的能够活动发挥,通过字节操作能够标记三十三个按钮,通过按键标识指标页面的部分性质,在拦截器中能够得到那几个标志进行作业逻辑推断
@Route(path = "/test/activity", extras = Consts.XXXX)

7.通过依赖注入解耦:服务管理(一卡塔尔(قطر‎ 揭发服务

// 声明接口,其他组件通过接口来调用服务
public interface HelloService extends IProvider {
    String sayHello(String name);
}

// 实现接口
@Route(path = "/service/hello", name = "测试服务")
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
    return "hello, "   name;
    }

    @Override
    public void init(Context context) {

    }
}

8.通过重视注入解耦:服务管理(二卡塔尔 开采服务

public class Test {
    @Autowired
    HelloService helloService;

    @Autowired(name = "/service/hello")
    HelloService helloService2;

    HelloService helloService3;

    HelloService helloService4;

    public Test() {
    ARouter.getInstance().inject(this);
    }

    public void testService() {
     // 1. (推荐)使用依赖注入的方式发现服务,通过注解标注字段,即可使用,无需主动获取
     // Autowired注解中标注name之后,将会使用byName的方式注入对应的字段,不设置name属性,会默认使用byType的方式发现服务(当同一接口有多个实现的时候,必须使用byName的方式发现服务)
    helloService.sayHello("Vergil");
    helloService2.sayHello("Vergil");

    // 2. 使用依赖查找的方式发现服务,主动去发现服务并使用,下面两种方式分别是byName和byType
    helloService3 = ARouter.getInstance().navigation(HelloService.class);
    helloService4 = (HelloService) ARouter.getInstance().build("/service/hello").navigation();
    helloService3.sayHello("Vergil");
    helloService4.sayHello("Vergil");
    }

概念贰个permissionActivity,让具备须要跳转权限的页面的activity世袭那么些,因为如上文讲的,大家其实权力的报名和拍卖不是在真正须求权限的页面达成,而是在上三个页面申请成功再跳到需求权限的页面包车型大巴。要是页面太多提出具备页面都三回九转这一个activity。

  1. Router内需开头化,用于初步化路由表,提出放手Application中做:

小结

官方的文书档案Github很详细能够去看看

以上办法得以拓宽简要的入门使用了,下一步我们从源码深入分析。

public class MainLooper extends Handler { private static MainLooper instance = new MainLooper(Looper.getMainLooper; protected MainLooper(Looper looper) { super; } public static MainLooper getInstance() { return instance; } public static void runOnUiThread(Runnable runnable) { if(Looper.getMainLooper().equals(Looper.myLooper { runnable.run(); } else { instance.post; } }}

时至明天,集成专门的职业就瓜熟蒂落了,简单的两步:增添插件路线和行使插件。那应当是看似框架中最简便易行的合龙方式了。

1.路由介绍

如何是路由框架?

说简洁明了点正是炫人眼目页面跳转关系的,当然它也蕴涵跳转有关的全体功效

干什么接受ARouter?

咱俩先从适用途景来深入分析:

  1. 动态跳转:常常的话复杂的电子商务跳转多页面要求很强的灵活性,非常多动静下是启使人陶醉士动态配置的行文活动页面,供给灵活的拓宽跳转。

  2. 组件化:随着业务量的不仅仅巩固,app也会不断的膨胀,开采共青团和少先队的范畴和职业量也会稳步增大,直面所衍生的64K难题、同盟开荒难题等,app平时都会走向组件化。组件化就是将APP遵照一定的功用和作业拆分成多个构件module,分化的零件独立开辟,组件化不仅能提供团体的工效,还是能够够抓牢利用品质。而组件化的前提正是解耦,那么大家第一要做的正是解耦页面之间的信赖关系

  3. Native与H5的难点:以往的APP很少是纯Native的,也超级少会有纯H5的,常常处境下都是将两端进行组合。那时候就供给非常省事并且统一的跳转方案,因为在H5中是无计可施选择StartActivity(State of Qatar跳转到Native页面包车型客车,而从Native跳转到H5页面也只可以通过配备浏览器的艺术落实

  4. 其它等情形

原生跳转方式的欠缺

  • 显式跳转, Intent intent = new Intent(activity, XXActivity.classState of Qatar;
    是因为供给一贯持有对应class,进而诱致了强信赖关系,进步了耦合度

  • 隐式跳转,举个例子 Intent intent = new Intent(卡塔尔(قطر‎; intent.setAction(“com.android.activity.MY_ACTION”);
    action等属性的定义在Manifest,引致了扩张性比较差
    平整集英式管理,引致合营变得要命费劲。

  • 原生的路由方案会不由自主跳转进程无法调控的标题,因为只要选拔了StartActivity(State of Qatar就不可能参预此中任何环节了,只可以交给系统管理,那就引致了在跳转战败的动静下不能降级,而是会直接抛出运维时的不行。

诸如此比完毕的利润也是显明的:全部的权杖申请操作都在拦截器里形成,对原代码无侵犯:全体的权柄申请弹框都冒出在急需权限的页面上二个activity。大家假若让这些activity世袭permissionActivity并管理onRequestPermissionsResult的回调就可以,别的诸如管理权限申请,管理权限申请成功,失利操作都合并在拦截器里做到就能够。

除开能够利用证明来加多路由外(上边步骤2介绍的点子State of Qatar,还足以因而代码手动调节路由表。

葡京网址,那就是说大家何不利用这几个拦截器,在跳到二个索要页面此前举行统一拦截,然后判断权限是还是不是富有,假使后则callback.onContinue,继续跳转,不然callback.onInterrupt,拦截跳转并实践权限申请。同一时间常常二个运用平日常有重中之重权限,无需权限制行驶使不恐怕不奇怪运行,如Manifest.permission.READ_PHONE_STATE,还会有非须求权限,如Manifest.permission.ACCESS_FINE_LOCATION。那么我们得以用priority字段创造优先级最高的拦截器,检查测验全数跳转时是不是有不可缺乏权限,不然先申请要求权限,然后继续触发下四个事情未发生前级低的拦截器拦截检查实验经常权限。

葡京网址 1QQ截图20170810160140.png

// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行 @Interceptor(priority = 8, name = "测试用拦截器")public class TestInterceptor implements IInterceptor { @Override public void process(Postcard postcard, InterceptorCallback callback) { callback.onContinue; // 处理完成,交还控制权 // callback.onInterrupt(new RuntimeException("我觉得有点异常")); // 觉得有问题,中断路由流程 // 以上两种至少需要调用其中一种,否则不会继续路由 } @Override public void init(Context context) { // 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次 }}

地方讲了足以因此路由传递参数,然后在对象页面通过Bundle获取,其实这么些历程也被Router简化了。通过@InjectParam解说可以为Activity大概Fragment的积极分子变量增加参数注入

Android6.0已经出去快七年了,除了一连推向Material Design,相信最直观的变改良是权力申请情势了:权限形式从一初叶的全部列出赋予,变成了前不久的运作时动态申请。下图列出了停止2月份流行的连串分占的额数。尽管碎片化难题照旧严重,但6.0以上系统分占的额数也已经八九不离十七半了。所以说各位安卓开辟者们,要是你的选取还未有适配6.0的话,可要紧紧抓住了。

Router还会有别的一些人性化的小成效,在这里处就不一一介绍了,有标题得以在档期的顺序主页提issue。后续会给大家疏解一下暗中的完成原理。

总结介绍了地方的三个概念后,大家切回正题。因为近些日子在做二个APP的组件化改造,原本的权柄适配方案是跳到二个空白activity做申请然后回调申请结果的,然而现在module与module之间是互不相信任的,所以activity之直接口回调的法子是行不通的。不平日间不知道有怎样好的办法,也参照了github上多少个主流的权力适配库,但缺憾都不曾对组件化应用提供叁个特意的化解方案。因为这么些项目选择的路由是Ali的ARouter。查阅文书档案后发觉里头有拦截器的效应,下边是大概的示范代码。

组件化应用的概念以来挺火的。随着app版本的迭代,业务也会变的一发复杂。组件化应用能将每种业务都独立分成叁个模块,作为三个零器件,业务模块相互互不依赖,然后让那个专门的学问模块都信任公共模块等,用路由的不二等秘书技代替startactivity开展模块间的跳转和多少传递。那正是组件化应用的简易概念。

该意义是Router最大的特征功用,差别于别的框架,Router并不曾显明路由的写法法规,而是抽象出Matcher的定义,交给顾客去决定。可是Router仍旧内置了4个常用的Matcher

实际上贯彻中有多少个注意点:1.拦截器init(Context context)措施中的context不是当前页的activity,而是application,相当于说你在拦截器里是不大概直接得到当前页的上下文的。所以你供给额外维护三个activity栈,在每种acitivity的oncreate()方法中入栈,在ondestory()中出栈,然后在拦截器里面抽出栈顶的acitivity,也正是当前页的acitivity。2.void process(Postcard postcard, InterceptorCallback callback)方法在子线程中推行,假如要实行权限申请需求先切换回主线程。

  1. 增添路由申明
public class PermissionActivity extends FragmentActivity { private PermissionListener permissionListener; public void setPermissionListener(PermissionListener permissionListener) { this.permissionListener = permissionListener; } /** * 权限请求结果 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (permissionListener != null ) { permissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults); } }

葡京网址 2MatcherRegistry相配优先级从高到低依次是DirectMatcherSchemeMatcherImplicitMatcherBrowserMatcher,关于原理就要后序的原理篇中举办教学。倘若好似下路由页面:

葡京网址 3u=3895375886,3606044301&fm=11&gp=0.jpg

  1. 在品种级的build.gradle中参加重视:

因为module与module之间是代码隔断的,互不注重,所以增加或移除module是很有利的,也方便了选拔的三人并行开荒。

@Interceptor(priority = 1)public class PermissionInterceptor implements IInterceptor { @Override public void process(final Postcard postcard, final InterceptorCallback callback) { final Activity activity = ActivityHelper.last(); final String[] PERMISSIONS = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, }; if (activity != null && !PermissionHelper.hasPermission) { permissionRequest(postcard, callback, (PermissionActivity) activity, permissions); } else { callback.onContinue; // 已有权限,无需申请,继续跳转 } } private void permissionRequest(final Postcard postcard, final InterceptorCallback interceptorCallback, final PermissionActivity activity, final String[] permissions) { Runnable runnable = new Runnable() { @Override public void run() { PermissionHelper.requestPermissions(activity, permissions, new PermissionListener() { @Override public void onsuccessed() { callback.onContinue;// 权限申请成功,继续跳转 } @Override public boolean onfail() { callback.onInterrupt;// 权限申请失败,拦截跳转 } }); } }; MainLooper.runOnUiThread(runnable ); } @Override public void init(Context context) { }}

其余功效正在拉长中...

Matcher支撑配置几个,会依据优先级依次举行相配。

  • @InjectParam会在Bundle中抽出对应key的值传给成员变量,暗许key为变量名,也能够通过key=""属性钦定
  • 参数注入扶助变量的暗中同意值,最近帮衬暗许值的变量类型有基本数据类型,String,CharSequence,别的品类的默许值都以null
  • 变量不提议利用private修饰符,因为个人的变量会接纳反射的方法注入参数
  • 要求选取Router.injectParams来兑现最后的参数注入
  1. 在module级的build.gradle中使用plugin:
// 定义拦截器@Interceptor("SampleInterceptor")public class SampleInterceptor implements RouteInterceptor { @Override public boolean intercept(Context context, @NonNull Uri uri, @Nullable Bundle extras) { // 返回true表示拦截当前路由 return true; }}// 定义拦截器Router.handleInterceptorTable(new InterceptorTable() { @Override public void handle(Map<String, Class<? extends RouteInterceptor>> map) { map.put("SampleInterceptor", SampleInterceptor.class); }});// 应用拦截器@Route(value = "test", interceptors = "SampleInterceptor")public class TestActivity extends AppCompatActivity { ...}// 应用拦截器Router.handleTargetInterceptors(new TargetInterceptors() { @Override public void handle(Map<Class<?>, String[]> map) { map.put(TestActivity.class, new String[]{"SampleInterceptor"}); }});

本文由新浦京81707con发布于注册购买,转载请注明出处:安卓组件化应用的6,Android路由框架Router分析

关键词: 路由 方案 Android 框架 组件

上一篇:自适应屏幕

下一篇:没有了