Android路由——ActivityRouter初识

1. 前言

如果大佬有兴趣可以直接到github中参考作者的说明文件进行学习。项目地址:ActivityRouter


之前看B站的组件化视频的时候,无意间了解到了ActivityRouter,这里就来简单的学习下这个开源的路由框架。

  • 支持Activity跳转、URL跳转;

2. 简单使用

按照学习的惯例,先来在一个项目中集成,然后简单使用下这个开源的框架。然后再尝试来阅读下ActivityRouter的源码。

按照github中的提示操作,我们在build.gradle(:app)中添加依赖:

implementation 'com.github.mzule.activityrouter:activityrouter:1.2.2'
annotationProcessor 'com.github.mzule.activityrouter:compiler:1.1.7'

当然这种方式为添加annotaitonProcessor方式。至于另一种apt方式我们这里就不再考虑。

然后在AndroidManifest.xml文件中的application标签中插入:

<activity android:name="com.github.mzule.activityrouter.router.RouterActivity"
          android:theme="@android:style/Theme.NoDisplay">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="weizu" /><!--改成自己的scheme-->
    </intent-filter>
</activity>

这里需要修改的android:scheme是在进行配置触发跳转时候所需要的一个类型标识,因为这个项目中支持多种方式,不再是我们简单案例中的Activity之间的跳转。我这里将之定义为weizu

然后,在项目中再添加一个OtherActivity并添加相应的xml文件,然后对其进行路由标识的关联,如下:

@Router("main")
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView viewById = findViewById(R.id.text);

        viewById.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Routers.open(MainActivity.this, "weizu://other");
            }
        });
    }
}
@Router("other")
public class OtherActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
    }
}

跳转命令也就是Routers.open(MainActivity.this, "weizu://other");

其链接的写法有点类似于常见的网络链接地址的书写。确实感觉很正式。

另不要忘记了在AndroidManifest.xml文件中注册OtherActivity

<activity android:name=".OtherActivity"/>

然后就可以实现点击后跳转。对于这个部分的实现,我觉得其逻辑应该和昨天的那个简单的案例中的一样,所以不妨来看看在这个项目中,这个部分的代码是如何实现的。当然,我们还需要测试不同模块下的Activity的跳转。

不妨新建一个test模块,我这里选择Android Library。由于我们之前的依赖添加在build.gradle(:app),所以在test中必不可以访问,所以这里还需要添加依赖。

但是经过测试发现模块之间的跳转却无法实现???

是我操作失误?是的!

在末尾我找到了:

支持多模块

  • 每个包含 activity 的 module 都要添加 apt 依赖
  • 每个 module(包含主项目) 都要添加一个 @Module(name) 的注解在任意类上面,name 是项目的名称
  • 主项目要添加一个 @Modules({name0, name1, name2}) 的注解,指定所有的 module 名称集合

但是还是不得行。。。

然后,我使用了build,然后找到了它生成了两个文件分别是RouterInitRouterMapping

RouterInit生成的内容如下:

public final class RouterInit {
  public static final void init() {
    RouterMapping.map();
  }
}

RouterMapping生成的内容如下:

import com.weizu.activityrouterstudy.MainActivity;
import com.weizu.activityrouterstudy.OtherActivity;

public final class RouterMapping {
  public static final void map() {
    java.util.Map<String,String> transfer = null;
    com.github.mzule.activityrouter.router.ExtraTypes extraTypes;

    transfer = null;
    extraTypes = new com.github.mzule.activityrouter.router.ExtraTypes();
    extraTypes.setTransfer(transfer);
    com.github.mzule.activityrouter.router.Routers.map("main", MainActivity.class, null, extraTypes);

    transfer = null;
    extraTypes = new com.github.mzule.activityrouter.router.ExtraTypes();
    extraTypes.setTransfer(transfer);
    com.github.mzule.activityrouter.router.Routers.map("other", OtherActivity.class, null, extraTypes);

  }
}

这里可以发现,其实思想是类似的。但是至于模块间的路由该如何实现确实勾起了我的好奇心。

难道真好换成apt 方式而不能使用annotaitonProcessor 方式来引入依赖?

毕竟作者是这样说的:

每个包含 activity 的 module 都要添加 apt 依赖

  • 至少到两个设计模式了,单例模式、解释器模式;确实我还没有用到,所以需要

一直感觉apt不就是注解处理器的缩写,这两者之间有什么差别吗?所以接下来我需要先找找这个问题的答案,因为这个项目2.8kstart可不是开玩笑的。

apt

但是在当我换成apt的时候,出现了下面的错误:

A problem occurred configuring project ':app'.
> android-apt plugin is incompatible with the Android Gradle plugin.  Please use 'annotationProcessor' configuration instead.

那么这两者之间到底有什么关系呢?感觉这篇讲的还可以:gradle之apt与annotationProcessor与kapt_火星男孩的分享空间-CSDN博客

annotationProcessor和android-apt的功能是一样的,它们是替代关系。

APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。

Android Gradle插件2.2版本发布后,Android 官方提供了annotationProcessor来代替android-apt,annotationProcessor同时支持 javac 和 jack 编译方式,而android-apt只支持 javac 方式。
同时android-apt作者宣布不在维护,当然目前android-apt仍然可以正常运行,如果你没有想支持 jack 编译方式的话,可以继续使用 android-apt。

也就是说,对于Gradle2.2以后,都使用Android官方提供的annotationProcessor,就不再使用android-apt。但是对于为什么多个模块之间没办法实现跳转,这里问题确实还需要学习下。

决定先使用阿里巴巴的ARouter来简单使用看看,然后再继续看看之前看的那个组件化开发的视频,看看模块间跳转大佬是如何做的。

ARouter

alibaba/ARouter

在这个github地址中,介绍了这个框架的使用,地址:ARouter/README_CN.md

在功能介绍中有:

  • 支持多模块工程使用

所以这个也就是我们目前学习所预期的。然后来体验下使用ActivityRouter没有实现的模块间的跳转。

当然在这之前,有个典型应用:

  1. 从外部URL映射到内部页面,以及参数传递与解析
  2. 跨模块页面跳转,模块间解耦
  3. 拦截跳转过程,处理登陆、埋点等逻辑
  4. 跨模块API调用,通过控制反转来做组件解耦

确实厉害!

还是上面的那个项目,也就是一个主模块,一个测试模块,然后我们去除在build.gradle中的ActivityRouter依赖,然后相应的在build.gradle(:app)中添加1和2:

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.weizu.activityrouterstudy"
        minSdkVersion 16
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        // 1
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    // 2
    implementation 'com.alibaba:arouter-api:1.5.0'
    annotationProcessor 'com.alibaba:arouter-compiler:1.5.0'

    implementation project(':test')
}

然后,我们需要按照说明进行SDK的初始化工作。即新建一个类,继承自Application,然后在这个类中完成初始化。

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ARouter.openLog();     // 打印日志
        ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
        ARouter.init(this); // 尽可能早,推荐在Application中初始化
    }
}

然后在AndroidManifest.xml配置,将之关联到整个应用,即:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:name="com.weizu.myapp.MyApp"
    android:theme="@style/Theme.ActivityRouterStudy">

然后我们为Activity添加注解,注意到:这里的路径需要注意的是至少需要有两级,如:

@Route(path = "/test/activity")
public class YourActivity extend Activity {
    ...
}

然后,我们就可以发起路由,这里我们只是为了体验,并不需要传递参数,所以这里就使用:

ARouter.getInstance().build("/test/activity").navigation();

对应的在app模块中的MainActivity代码如下:

@Route(path = "/app/main")
public class MainActivity extends AppCompatActivity {
    private String TAG = "Main";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView viewById = findViewById(R.id.text);

        viewById.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ARouter.getInstance().build("/app/other").navigation();
            }
        });
    }
}

OtherActivity代码如下:

@Route(path = "/app/other")
public class OtherActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
    }
}

然后测试结果正常。

现在我们开始在test模块中添加一样的1和2的依赖,然后添加路由,如:

@Route(path = "/test/another")
public class AnotherActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

最后发现不得行,嗯??看来在ActivityRouter中也是我操作的问题。

然后我修改了这个OtherActivity布局文件的名字叫做activity_another,最后在app模块中加载的那个activity_main居然也变了。所以这里的问题一定是我文件名命名整相同的问题。所以重新修改后,在AnotherActivity中加载activity_another

最终测试跳转结果正常。

看来有必要重新来使用ActivityRouter再试一次。

先清除ARouter中的相关依赖,然后再添加annotaitonProcessor方式的ActivityRouter依赖:

dependencies {
    compile 'com.github.mzule.activityrouter:activityrouter:1.2.2'
    annotationProcessor 'com.github.mzule.activityrouter:compiler:1.1.7'
}

AndroidManifest.xml配置:

<activity
   android:name="com.github.mzule.activityrouter.router.RouterActivity"
    android:theme="@android:style/Theme.NoDisplay">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="mzule" /><!--改成自己的scheme-->
    </intent-filter>
</activity>

对于app/MainActivity

@Router("main")
@Module("main")
@Modules({"main", "test"})
public class MainActivity extends AppCompatActivity {
    private String TAG = "Main";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView viewById = findViewById(R.id.text);

        viewById.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Routers.open(MainActivity.this, "weizu://other");
            }
        });
    }
}

对于app/OtherActivity

@Router("other")
@Module("main")
public class OtherActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
    }
}

模块内Activity跳转正常。

然后我们修改下app/MainActivity中的跳转路由:

Routers.open(MainActivity.this, "weizu://another");

模块之间的Activity跳转正常。

我可真是个废物,不过还好要吸取教训!

也就是不同模块之间的xml文件还是要遵守规范,比如:

Activity_name_modulename.xml

所以接下来我们需要阅读下ActivityRouter的源码。理解其中涉及到的一些设计模式和设计思想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦否

文章对你有用?不妨打赏一毛两毛

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值