zoukankan      html  css  js  c++  java
  • ARouter 拦截器之多 module 独立运行

    本文已首发微信公众号「code小生」,大家可以搜索关注,专注安卓技术分享。

    本文说明

    上篇文章已分享了路由配置、跳转、原理、完整的效果演示gif以及源码,而且是多 module 项目演示的,算是路由 ARouter 的入门,还没配置使用的可以先去看看。

    本文的内容主要涉及如下两个:

    • 路由拦截器使用
    • module 独立运行

    前者在我们开发中有这样一种应用场景,默认用户不登录可以浏览一部分页面,当点击部分页面的时候就需要先去登录,也就是跳转到登录页面,普通的做法是根据需求挨个去做点击事件,这就很麻烦,如果需要跳转登录的时候传递参数啥的,那就改动超级大了;而路由ARouter的拦截器功能就很好的解决了这个问题,还支持自定义拦截器,使用起来很灵活。

    后者的使用场景适合项目大,多人开发的情景,这样可以各自负责一个模块,独立调试运行,利于项目管理以及代码的维护。这块在上一篇文章的前提下还需要额外配置,本文会讲。

    module 独立运行

    先来看看module独立运行,然后我们在各个模块做一个模拟的跳转页面需要验证登录的示例,这样比较清晰。

    第一步:配置 gradle.properties

    gradle.properties 文件中添加如下代码

    #是否需要单独运行某个模块 true:表示某个模块不作为依赖库使用
    isSingleCircleModule=true
    #isSingleCircleModule=false
    isSingleHomeModule=true
    #isSingleHomeModule=false
    

    第二步:配置app下的build.gradle

    在app下的build.gradle文件配置

    if (!isSingleCircleModule.toBoolean()) {
        implementation project(path: ':circle')
    }
    if (!isSingleHomeModule.toBoolean()){
        implementation project(path: ':home')
    }
    

    并注释掉原来的依赖

    //    implementation project(path: ':circle')
    //    implementation project(path: ':home')
    

    第三步:配置各独立模块下的build.gradle

    circle模块下build.gradle文件最顶部改动如下:

    //plugins {
    //    id 'com.android.library'
    //}
    
    if (isSingleCircleModule.toBoolean()) {
        apply plugin: 'com.android.application'
    } else {
        apply plugin: 'com.android.library'
    }
    

    home模块下build.gradle文件最顶部改动如下:

    //plugins {
    //    id 'com.android.library'
    //}
    
    if (isSingleHomeModule.toBoolean()) {
        apply plugin: 'com.android.application'
    } else {
        apply plugin: 'com.android.library'
    }
    

    第四步:看效果

    上面的配置完成后,点击Sync Project with Gradle Files 等待编译完成,可看到如下状态:

    Select Run弹窗

    这个时候我们选择其中一个module运行,会发现报错如下:

    Could not identify launch activity: Default Activity not found
    Error while Launching activity
    

    很明显,我们都知道Android程序的主入口是从清单文件配置的,但我们的各module都还没有做这个工作。

    circle模块下的清单文件中,配置如下:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.gs.circle">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/app_icon"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".CircleActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    其中的iconlabel以及theme都可以定义在baselib中,这样我们任何 module 配置的时候就可以直接引用,而无需各自复制一份了;除此之外,values文件夹下的东西都可以移动到baselib下,方便其他模块引用,这也就是baselib模块的作用,如果你要细分,还可以j将公共资源放在一个独立的模块里,这个模块通常叫做:commonlib,具体情况而定。

    配置完清单文件,运行后发现桌面会多出来一个 APP icon,打开只有一个页面,就是我们的circlemodule的主页面。home模块的清单配置就不展示了,下面看下效果:

    module独立运行

    这个时候再切回去运行app模块,如果发现有问题,先卸载再运行就ok了。但是会有一个问题,原来可以跳转其他模块的功能,现在跳转不了了,这其实很正常,因为在组件化开发模式下,每个 module 都是独立的app,所以肯定不能直接跳转过去。

    那如何实现正常跳转呢?

    需要两步,将gradle.properties中的代码修改为如下:

    #isSingleCircleModule=true
    isSingleCircleModule=false
    #isSingleHomeModule=true
    isSingleHomeModule=false
    

    接着将circlehome模块的清单文件中的 application属性和默认启动配置项删掉,然后再运行就 ok 了。

    如果想将其中一个作为依赖库使用,那么就指匠情挑设置为false即可。

    关于组件之间 AndroidManifest 合并问题

    其实这个可以在正式打包的时候,注释掉module中的相关代码即可,毕竟是在组件模式。那有没有办法解决每次都要注释的问题呢?答案是yes.

    大致思路如下:

    在可独立运行的module的res->main文件夹下新建一个文件夹(命名自定义),然后将对应的清单文件复制一份,名称不需要修改,内容的差别就是前面提到的,去掉application属性和默认启动配置项。

    接着在对应 module 的 build.gradle 中指定表单的路径,代码如下:

    sourceSets {
        main {
            if (isSingleCircleModule.toBoolean()) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }
    

    这样在不同的开发模式下就会读取到不同的 AndroidManifest.xml ,然后我们需要修改这两个表单的内容以为我们不同的开发模式服务。

    单模块独立运行小结

    优点:

    • 项目耦合度低,开发效率高,出现问题易排查
    • 利于项目进度管理,分工明确
    • 适合多人大项目

    缺点:

    • 前期配置比较复杂,开发过程中需要修改部分配置
    • 稳定性不好把握,毕竟不是google官方出的框架,后期出问题不好处理

    其实还有很多问题,实践过的应该明白,每个项目都有自己的独特之处,会有各种各样的奇怪问题,但一般网上我们都可以找到解决方案。

    路由拦截器使用

    首先还是需要添加几个配置,在工程下的build.gradle文件中添加下面这行代码:

    classpath 'com.alibaba:arouter-register:1.0.2'
    

    app模块的build.gradle文件下,配置改动如下:

    plugins {
        id 'com.android.application'
        id 'com.alibaba.arouter' // 拦截器必须配置
    }
    

    配置完这两步,按照惯例,该是编译了。

    为了演示,我这里在app下新建一个名为LoginActivity的页面,作业登录拦截后跳转的页面,页面内容只有一个提示文本,这里补贴代码。

    然后分别在宿主模块app、功能模块circlehome中去做跳转登录页面,看看我们的拦截器是否起到了拦截作用,下面开始定义拦截器。

    要独立运行某个模块,这里就不再赘述了,大家自行修改配置即可。

    拦截器完整代码如下:

    /**
     * Description: 登录拦截器
     * Date: 2021/10/9 10:42
     * <p>
     * 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
     * * <p>
     * * priority 数值越小权限越高
     */
    @Interceptor(priority = 2, name = "登录ARouter拦截器")
    public class LoginInterceptor implements IInterceptor {
    
        private Context mContext;
    
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
            boolean isLogin = mContext.getSharedPreferences("arouterdata", mContext.MODE_PRIVATE).getBoolean("isLogin", false);
            if (isLogin) {
                callback.onContinue(postcard);
            } else {
                switch (postcard.getPath()) {
                    // 需要登录的拦截下来
                    case ARouterPath.APP_MY_INFO:
                        ARouter.getInstance().build(ARouterPath.LOGIN_PAGE).with(postcard.getExtras()).navigation();
                        break;
                    default:
                        callback.onContinue(postcard);
                        break;
                }
            }
        }
    
        /**
         * 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
         *
         * @param context
         */
        @Override
        public void init(Context context) {
            mContext = context;
        }
    
    }
    

    拦截器初始化需要重新安装才会生效,这点要注意。拦截器是不需要我们手动显示调用的,而是框架通过注解来使用的,所以我们只需要写好逻辑代码即可。

    以上代码可以实现模块内和跨模块跳转拦截,本地的登录状态我这里没有处理逻辑,所以每次都会被拦截到。下面看效果:

    拦截器效果

    演示效果模拟进入MyInfoActivity页面时需要先登录,分别从三个模块做了跳转演示。

    总结

    组件化module独立运行与合并操作起来相对繁琐一点,但优点也很明显。路由框架ARouter的拦截器使用起来就很简单了,其实拦截器完全可以在学完上一篇之后,直接使用,如果组件化多模块独立运行实际项目使用不到,可以先跳过,简单了解流程即可。

    Android的框架演变也很快,“三化技术”在两年前特别火,几乎大家都在讨论,但并没有持续多长时间就被新出的技术替代了,而作为一个开发者,自己需要掌握一个基本技能:从零开始搭建一个项目框架,并且这个框架尽可能的要跟上项目的持续发展

    本文全部代码已打包:关注微信公众号code小生回复arouter

  • 相关阅读:
    系统编码、文件编码与python系统编码
    python2判断编码格式
    android: 对apk进行系统签名
    android: 对普通的apk应用进行签名
    android studio: 设置单条注释不换行
    Gradle: Could not determine the dependencies of task ':app:processDebugResources'解决(转)
    android Dialog: 去除dialog 顶部 蓝色的线
    android:Error:” ” is not translated in “en” (English) [MissingTranslation]处理方法(转)
    android: 通过Intent筛选多种类型文件
    GIt: git rebase 和 git merge 的区别 (转)
  • 原文地址:https://www.cnblogs.com/codexs/p/15451128.html
Copyright © 2011-2022 走看看