Android路由框架ARouter的使用示例

编辑: admin 分类: Android 发布时间: 2021-11-29 来源:互联网
目录
  • 一、添加依赖和初始化框架
    • 1、添加依赖
      • 1.1、java版本的依赖
      • 1.2、kotlin版本的依赖
    • 2、初始化SDK
    • 二、ARouter的简单使用
      • 1、界面跳转
        • 1.1、Activity界面跳转
        • 1.2、获取fragment实例
        • 1.3、注意事项
      • 2、携带基本参数的界面跳转
        • 3、携带对象的界面跳转
          • 3.1、携带序列化对象的界面跳转
          • 3.2、携带无序列化对象的界面跳转
          • 3.3、携带集合和数组的界面跳转
        • 4、界面跳转回调
          • 5、未用到的知识点

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

          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的使用的资料请关注海外IDC网其它相关文章!

          【文章转自:韩国cn2服务器 转载请保留连接】