Android路由框架ARouter的使用示例

 更新时间:2021年6月18日 10:00  点击:1391

一、添加依赖和初始化框架

1、添加依赖

在需要使用ARouter的module中添加如下代码:

1.1、java版本的依赖

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

dependencies {
    api 'com.alibaba:arouter-api:1.5.1'
    annotationProcessor 'com.alibaba:arouter-compiler:1.5.1'
}

1.2、kotlin版本的依赖

plugins {
    ...
    id 'kotlin-kapt'
}

dependencies {
    ...
    implementation 'com.alibaba:arouter-api:1.5.1'
    kapt 'com.alibaba:arouter-compiler:1.5.1'
}

题外话: implementation 和 api 关键字,在Android studio3.0版本中,曾经的 compile 关键字被弃用,而 api 则是 compile 的替代品, api 与 compile 没有区别。但最新官方推荐使用 implementation 来代替 compile 关键字,据说 implementation 会使Android studio的编译速度更快呦。

而 implementation 和 api 关键字的区别则在于用 implementation 来声明的依赖包只限于当前module内部使用,对于依赖其module的模块是无法使用到该依赖包的。而用 api 来声明依赖包时,依赖于该module的模块可以正常使用其模块内的依赖包。

在这里,由于我是将其放入一个公共的module,来让app module进行依赖,因此使用 api 关键字。若没有对项目进行组件化,则可以使用 implementation 关键字进行依赖。

2、初始化SDK

//初始化ARouter框架
private boolean isDebugARouter = true;//ARouter调试开关
if (isDebugARouter) {
    //下面两行必须写在init之前,否则这些配置在init中将无效
    ARouter.openLog();
    //开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!
    // 线上版本需要关闭,否则有安全风险)
    ARouter.openDebug();
}
//官方推荐放到Application中初始化
ARouter.init((Application) mContext);

二、ARouter的简单使用

1、界面跳转

1.1、Activity界面跳转

目标Activity添加注释(跳转语句,路由路径建议写成常量,创建路由表进行统一管理。)

@Route(path = "/app/login")
public class LoginActivity extends AppCompatActivity {

发送Activity实现跳转到

ARouter.getInstance().build("/app/login").navigation();

1.2、获取fragment实例

//目标界面
@Route(path = "/app/fragment")
public class EmptyFragment extends BaseFragment {
}

//启动界面
Fragment fragment= (Fragment) ARouter.getInstance().build("/app/fragment").navigation();
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.fl_fragment_content, fragment);
transaction.commit();

1.3、注意事项

如果像我一样对项目进行了组件化的同学就会发现,此时跳转并没有成功,而是弹出错误提示。

这是因为组件化后,即时我们使用了 api 作为依赖的关键字,但仍需在使用ARouter的其他module中配置代码。这里一般习惯的做法是把arouter-api的依赖放在基础服务的module里面,因为既然用到了组件化,那么肯定是所有的module都需要依赖arouter-api库的,而arouter-compiler的依赖需要放到每一个module里面。

java

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

dependencies {
    annotationProcessor 'com.alibaba:arouter-compiler:1.5.1'
}

kotlin

plugins {
    ...
    id 'kotlin-kapt'
}

dependencies {
    ...
    kapt 'com.alibaba:arouter-compiler:1.5.1'
}

否则无法匹配路由,并且在使用withObject方法携带对象时也会报错,这个后面再说,再试一次发现界面成功跳转。关于注释 @Route 的 path 参数,也需要注意规范,必须要以“/”开头,并且路径至少为两级,不然会编译不通过或者报错。

意思是路径必须以“/”开头,并且包含的值超过2个“/”。

2、携带基本参数的界面跳转

使用方法如下,传入键值对

Bundle bundle = new Bundle();
bundle.putString("bundleStringKey", "bundleStringValue");

ARouter.getInstance().build("/app/login")
             .withString("stringKey", "stringValue")
             .withInt("intKey", 100)
             .withBoolean("booleanKey", true)
             .withBundle("bundle", bundle)
             .navigation();

目标界面使用 @Autowired 注解进行注入

@Route(path = "/app/login")
public class LoginActivity extends AppCompatActivity {
    @Autowired
    String stringKey;
    @Autowired
    int intKey;
    @Autowired
    boolean booleanKey;
    @Autowired
    Bundle bundle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        //注入ARouter
        ARouter.getInstance().inject(this);
        
        Log.e(TAG, stringKey + "..." + intKey + "..." + booleanKey);
        Log.e(TAG, bundle.getString("bundleStringKey"));
    }
}

注意:注入的属性名要和之前携带的key值完全相同,并且要在需要注入的界面通过ARouter.getInstance().inject(this)注入ARouter,否则无法注入成功。建议将ARouter.getInstance().inject(this)操作放在BaseActivity的onCreate方法中进行。既然有注入,就一定有资源的释放,因此释放资源在Application中进行。

    @Override
    public void onTerminate() {
        super.onTerminate();
        ARouter.getInstance().destroy();
    }

如果释放资源放在BaseActivity的onDestroy方法中调用了 ARouter.getInstance().destroy( ) ; 在进入目标Activity之后,然后按back键返回原界面的时候,APP会报错崩溃,下面是崩溃日志:

3、携带对象的界面跳转

3.1、携带序列化对象的界面跳转

携带 Serializable 和 Parcelable 序列化的对象

TestSerializableBean serializableBean = new TestSerializableBean();
serializableBean.setName("serializable");

TestParcelableBean parcelableBean = new TestParcelableBean();
parcelableBean.setName("parcelable");

ARouter.getInstance().build("/app/login")
        .withParcelable("parcelableBean", parcelableBean)
        .withSerializable("serializableBean", serializableBean)
        .navigation();

目标界面

@Autowired
TestParcelableBean parcelableBean;
@Autowired
TestSerializableBean serializableBean;

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        Log.e(TAG, parcelableBean + "");
        Log.e(TAG, serializableBean + "");
}

我们发现Serializable序列化的对象为null,我们查看withSerializable方法发现其被装进了Bundle

public Postcard withSerializable(@Nullable String key, @Nullable Serializable value) {
        mBundle.putSerializable(key, value);
        return this;
    }

因此换一种方法来取值,发现打印成功

TestSerializableBean serializableBean = (TestSerializableBean) getIntent().getExtras().getSerializable("serializableBean");
Log.e(TAG, serializableBean + "");

3.2、携带无序列化对象的界面跳转

没有进行过序列化的对象也可以通过withObject对象进行传递,接收方式相同

NormalTest normalTest = new NormalTest();
normalTest.setName("normal");
ARouter.getInstance().build("/app/login")
        .withObject("normalTest", normalTest)
        .navigation();

但是我们直接使用该方法运行会报错,分析源码发现该方法中用到了SerializationService

    public Postcard withObject(@Nullable String key, @Nullable Object value) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        mBundle.putString(key, serializationService.object2Json(value));
        return this;
    }

因此我们需要实现该服务

@Route(path = "/service/json")
public class JsonServiceImpl implements SerializationService {
    private Gson gson;

    @Override
    public <T> T json2Object(String input, Class<T> clazz) {
        return gson.fromJson(input, clazz);
    }

    @Override
    public String object2Json(Object instance) {
        return gson.toJson(instance);
    }

    @Override
    public <T> T parseObject(String input, Type clazz) {
        return gson.fromJson(input, clazz);
    }

    @Override
    public void init(Context context) {
        gson = new Gson();
    }
}

我们可以在里面定义所需的json解析器,再次运行成功打印该对象。那序列化的对象可以使用该方法传递吗?

TestParcelableBean objParcelableBean = new TestParcelableBean();
objParcelableBean.setName("objParcelable");

TestSerializableBean objSerializableBean = new TestSerializableBean();
objSerializableBean.setName("objSerializable");

NormalTest normalTest = new NormalTest();
normalTest.setName("normal");

ARouter.getInstance().build("/app/login")
        .withObject("objParcelableBean", objParcelableBean)
        .withObject("objSerializableBean", objSerializableBean)
        .withObject("normalTest", normalTest)
        .navigation();

//目标界面
@Autowired(name = "objParcelableBean")
TestParcelableBean objParcelableBean;
@Autowired(name = "objSerializableBean")
TestSerializableBean objSerializableBean;
@Autowired(name = "normalTest")
NormalTest normalTest;

Log.e(TAG, objParcelableBean + "");
Log.e(TAG, objSerializableBean + "");
Log.e(TAG, normalTest + "");

我们发现用 Parcelable 序列化的对象为空,分析build的编译文件

@Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    LoginActivity substitute = (LoginActivity)target;
    substitute.objParcelableBean = substitute.getIntent().getParcelableExtra("objParcelableBean");
    if (null != serializationService) {
      substitute.objSerializableBean = serializationService.parseObject(substitute.getIntent().getStringExtra("objSerializableBean"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestSerializableBean>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'objSerializableBean' in class 'LoginActivity' , then you should implement 'SerializationService' to support object auto inject!");
    }
    if (null != serializationService) {
      substitute.normalTest = serializationService.parseObject(substitute.getIntent().getStringExtra("normalTest"), new com.alibaba.android.arouter.facade.model.TypeWrapper<NormalTest>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'normalTest' in class 'LoginActivity' , then you should implement 'SerializationService' to support object auto inject!");
    }
  }

我们可以看到唯独通过 Parcelable 方式序列化的对象没有使用SerializationService进行解析,而是直接从Bundle去取,但我们并不是通过withParcelable方法去设置的值,因此取得的数据为null。

小结:因此,为了方便我们的操作,没有序列化和使用 Serializable 序列化的对象使用 withObject 方法传递,使用 Parcelable 方式序列化的对象则采用 withParcelable 方法进行传递。

3.3、携带集合和数组的界面跳转

集合和数组的界面跳转统一使用 withObject 方法传递,并且能够支持成员的各种序列化方式。

 List<NormalTest> listNormal = new ArrayList<>();
 listNormal.add(new NormalTest());
 listNormal.add(new NormalTest());

 List<TestSerializableBean> listSerializable = new ArrayList<>();
 listSerializable.add(new TestSerializableBean());
 listSerializable.add(new TestSerializableBean());

 List<TestParcelableBean> listParcelable = new ArrayList<>();
 listParcelable.add(new TestParcelableBean());
 listParcelable.add(new TestParcelableBean());

 Map<String, NormalTest> map = new HashMap<>();
 map.put("1", new NormalTest());
 map.put("2", new NormalTest());

 ARouter.getInstance().build("/app/login")
         .withObject("listNormal", listNormal)
         .withObject("listSerializable",listSerializable)
         .withObject("listParcelable",listParcelable)
         .withObject("map", map)
         .navigation();

 //目标界面
 @Autowired
 List<NormalTest> listNormal;
 @Autowired
 List<TestSerializableBean> listSerializable;
 @Autowired
 List<TestParcelableBean> listParcelable;
 @Autowired
 Map<String, NormalTest> map;

 Log.e(TAG, listNormal + "");
 Log.e(TAG, listSerializable + "");
 Log.e(TAG, listParcelable + "");
 Log.e(TAG, map + "");

4、界面跳转回调

//启动界面
ARouter.getInstance().build("/app/login")
        .navigation(MainActivity.this, REQUEST_CODE);

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE&& resultCode == RESULT_CODE) {
            LogUtils.e(data.getStringExtra("data"));
        }
    }


//目标界面
Intent intent = new Intent();
intent.putExtra("data", "resultData");
setResult(RESULT_CODE, intent);
finish();

5、未用到的知识点

由于项目中没有用到ARouter拦截器、ARouter自定义分组,这两块知识点,所以就没研究。

以上就是Android路由框架ARouter的使用示例的详细内容,更多关于Android路由框架ARouter的使用的资料请关注猪先飞其它相关文章!

[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • vue 实现动态路由的方法

    这篇文章主要介绍了vue 实现动态路由的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-06
  • 基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍

    这篇文章主要介绍了基于BootStrap Metronic开发框架经验小结【八】框架功能总体界面介绍 的相关资料,需要的朋友可以参考下...2016-05-14
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • CI框架开发新浪微博登录接口源码完整版

    首先来看下流程:流程原理: 1.通过code获得access_token通过授权,并获取用户的信息(包括用户u_id)(这个u_id在后面的第三方登录表里面叫sina_id,那个表是需要自己建的) 2.查询第三方登录表,如果不存在用户sina_id,分2...2014-05-31
  • .net数据库操作框架SqlSugar的简单入门

    这篇文章主要介绍了.net数据库操作框架SqlSugar的简单入门,帮助大家更好的理解和学习使用.net技术,感兴趣的朋友可以了解下...2021-09-22
  • 记一次EFCore类型转换错误及解决方案

    这篇文章主要介绍了记一次EFCore类型转换错误及解决方案,帮助大家更好的理解和学习使用asp.net core,感兴趣的朋友可以了解下...2021-09-22
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • 解决vue动态路由异步加载import组件,加载不到module的问题

    这篇文章主要介绍了解决vue动态路由异步加载import组件,加载不到module的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20