开发者社区> 菜刀文> 正文

谈谈App的统一跳转和ARouter

简介: App中每次页面跳转,都需要调用统一导航, 它用的非常频繁, 有必要对它进行一下梳理. 让他能用起来简单方便, 同时能支持各种常用的跳转业务场景.
+关注继续查看

App中每次页面跳转,都需要调用统一导航, 它用的非常频繁, 有必要对它进行一下梳理. 让他能用起来简单方便, 同时能支持各种常用的跳转业务场景.

一. Android跳转遇到的问题

1.intent-filter跳转不好管理

 Intent intent = new Intent();  
 intent.setAction(Intent.ACTION_SENDTO);  
 intent.setData(Uri.parse("smsto:10086"));  
 context.startActivity(intent);  

如果项目分多个Module, Activity需要在各自Module的AndroidManifest.xml中声明,容易重复,不好统一管理.

2.Activity class跳转耦合性高

//通过设置目标class跳转 
Intent intent = new Intent();  
intent.setClass(context,TargetActivity.class);  
context.startActivity(intent);  

A如果要跳转到TargetActivity, A要引用到TargetActivity. 造成:

  1. 如果项目多个Module开发,底层module不能跳转到高层Activity
  1. 如果TargetActivity类名变化, 对应调用方都需要改动

3. 混合开发时,H5/Weex跳转新界面不方便

内置H5要跳转 Native页面, 通过JsBidge把目标信息传过来.

两种方式:

方式1: 直接提供目标Activity的 Action 跳过去.
方式2: Native维护一个<描述,Activity信息>的Map, H5传过来Activiy的"描述", Native在Map中查到后,进行跳转.

方式1的问题:

一般H5会同时在"Android/ios"容器中, 所以最好的实践是:H5做跳转时不需要区分平台和版本. 如果利用Action跳转,

1)Action命名要符合两个平台的规范

2)如果Native不支持目标Action,还需要做跳转失败后处理.

方式2的问题:

1)维护<描述,Activity信息>的列表麻烦事,需要单独角色管理.

2)同样存的"Activity信息"也有问题1,2中提到的问题

都有的问题:

处理跳转的Bridge类,可能拿不到context,这需要拿Application的Context,大家都判断略嫌麻烦.

4.跳转到"未知页面"的统一处理

比如2.0版本新加了"消息"功能,App1.0版本没有.
此时1.0版本的App中,"H5/push" 尝试打开"消息"页面, 肯定是不支持的. 这时候有几种策略:

  1. H5/Push能判断Native支持页面的能力,如果不支持,就不调用
  2. Native收到调用未知页面, 不做任何动作.
  3. Native收到调用未知页面, 提示这是新版功能,建议更新版本.

5. 业务降级/重定向

  1. 比如A/B测试:
    Native可以根据配置, 跳转不同的实现页面
  2. 业务降级:
    某个业务本来Native实现, 降级为H5实现, 这时候跳转时切换到H5页面.

6.统一加参

跳转到目标页面前,能统一加参数.
实现比如打点, 添加通用参数操作.

7.外部调用的统一入口

考虑这种业务场景: App有 A,B,C三个页面, 提供给外部调用.
这时候一般两种实现方式:

方式1: A,B,C的Activity 在AndroidManifest.xml中export=true,并且设置 intent-filter
方式2: App设置一个统一的Router-Activity, 外部跳转到A,B,C 都统一先统一到Router-Activity, 他在拉起A,B,C

方式1分析:

除非真的提供通用的功能(拍照/图片处理/..)给外部调用, 否则export一个Activity是不必要也不安全的. 为了安全,App不会export大量的Activity. 这意味着通过这种机制, 外部能调用内部的功能较少.

方式2分析:

优点:

  1. 只暴露了一个Router-Activity. 安全和好管理.
  2. Router-Activity里面可以做一些调用者的安全校验, 如果校验通过可以运行跳转App的全部页面. 这样给能外部调用app更多页面的机会, 也兼顾了安全.

缺点:
外部跳转需要一个Activity中转一下,直观上感觉效率低一些. 但是实际感觉基本没有影响.

二. 明确需求

根据问题和业务场景, 我们的"统一跳转"的需求也基本明确:

  1. "声明/使用" 简单.
  1. 适用多module开发,避免直接依赖.
  2. 统一协议, 适用"H5/Weex/Native" 跳转 "Native", 对"Android/ios"两个平台协议应该是一样的.
  3. 有统一的外部调用入口
  4. 能对"不支持"的跳转统一处理
  5. 支持跳转前预处理
  6. 支持重定向

三.解决方案ARouter

ARouterARouter-github 很好的解决了上述问题.
下面是他的对应的方案.

1.使用简单:

  1. 每个Activity在类中自声明,"代码-路径"对应一目了然
@Route(path = "/test/activity")
public class YourActivity extend Activity {
    ...
}
  1. 跳转新页面简单,不需要知道目标ActivityContext,intent-filter,目标的Activity
ARouter.getInstance().build(path).with(bundle).navigation();   

2.页面利于统一管理

所有页面可以统一定义. 一目了然

String PAGE_MAIN = "/navigateTo/main";
String PAGE_H5 = "/navigateTo/h5";
String PAGE_WEEX = "/navigateTo/weex";
...

3.便于设置统一Activity承载外部跳转

public class SchameFilterActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //安全/版本校验
    ....
    
    Uri uri = getIntent().getData();
    ARouter.getInstance().build(uri).navigation();
    finish();
    }
}

4.处理"未知页面"的跳转结果

 ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
    @Override
    public void onFound(Postcard postcard) {
      ...
    }
    @Override
    public void onLost(Postcard postcard) {
        //可以处理,提示升级版本之类
    }
});

5. 自定义全局降级策略

// 实现DegradeService接口,并加上一个Path内容任意的注解即可
@Route(path = "/xxx/xxx")
public class DegradeServiceImpl implements DegradeService {
  @Override
  public void onLost(Context context, Postcard postcard) {
    // do something.
  }

  @Override
  public void init(Context context) {

  }
}

6. 重写跳转URL实现重定向

// 实现PathReplaceService接口,并加上一个Path内容任意的注解即可
@Route(path = "/xxx/xxx") // 必须标明注解
public class PathReplaceServiceImpl implements PathReplaceService {
    /**
     * For normal path.
     *
     * @param path raw path
     */
    String forString(String path) {
    return path;    // 按照一定的规则处理之后返回处理后的结果
    }

   /**
    * For uri type.
    *
    * @param uri raw uri
    */
   Uri forUri(Uri uri) {
    return url;    // 按照一定的规则处理之后返回处理后的结果
   }
}

技术分析

1.建立 Url-Activity 的对应关系

ARouter最后是通过下面方式跳转的.

//_ARouter.java  
Intent intent = new Intent(currentContext,postcard.getDestination());
intent.putExtras(postcard.getExtras());

所以要AROUTER需要维护一个 Path和Activity class的对应关系.
他利用

  1. javapoet 在编译时候生成类信息
  2. 初始化时,收集主创Path/Activity信息. 所有信息存在WareHouse中.

screenshot.png

2. 跳转流程

screenshot.png

其他技术

1. 属性设置在gradle.properties中

BUILDTOOLS_VERSION=25.0.0

使用:

compile "com.android.support:support-v4:${SUPPORT_LIB_VERSION}"   
buildToolsVersion BUILDTOOLS_VERSION

2.TreeMap

HashMap通过hashcode对其内容进行快速查找,而 TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)

3.Instrumentation的使用

你可以将Instrumentation理解为一种没有图形界面
的,具有启动能力的,用于监控其他类(用Target
Package声明)的工具类。任何想成为Instrumentation的类必须继承android.app.Instrumentation。

下面是这个类的解释:

“Base class for implementing application instrumentation code. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's tag.“

4.volatile

Java多线程/并发09、浅谈volatile

  1. volatile重要工作是避免线程脏读:当线程对volatile变量进行读操作时,会先将2. 自己工作内存中的变量置为无效,之后再通过主内存拷贝新值到工作内存中使用。
  2. volatile解决的是变量在多个线程之间的可见性,但不能完全保证数据的原子性。
    现在JVM经过优化,已不会出现liveness failure 。所以没事别用volatile。

5. CountDownLatch

CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。

6.获取CPU个数

CPU_COUNT = Runtime.getRuntime().availableProcessors()

7.捕捉线程异常

// 捕获多线程处理中的异常
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        ARouter.logger.info(Consts.TAG, "Running task appeared exception! Thread [" + thread.getName() + "], because [" + ex.getMessage() + "]");
       }
   }); 

8.javapoet

build  classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' 

使用 annotationProcessor
dependencies {
    annotationProcessor project(':arouter-compiler')
}

9.Activity启动

int flags = postcard.getFlags();
    if (-1 != flags) {
      intent.setFlags(flags);
    } else if (!(currentContext instanceof Activity)) {     
    // Non activity, need less one flag.
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} 

10. 访问者模式

//设置WareHouse

public interface IRouteGroup {
    /**
     * Fill the atlas with routes in group.
     */
    void loadInto(Map<String, RouteMeta> atlas);
}

iGroupInstance.loadInto(Warehouse.routes);

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
iOS app跳转到系统设置页面方法
iOS app跳转到系统设置页面方法
20 0
React Native |App里跳转到系统应用设置
React Native |App里跳转到系统应用设置
128 0
微信分享和微信H5跳转到APP开放标签wx-open-launch-app使用及样式设置
微信分享和微信H5跳转到APP开放标签wx-open-launch-app使用及样式设置
798 0
iOS - 跳转App Store下载 app 的两种方式
iOS - 跳转App Store下载 app 的两种方式
1541 0
H5 跳转到app或者应用商店 vue3 hook写法
H5 跳转到app或者应用商店 vue3 hook写法
309 0
Android跳转到应用商店的APP详情页面,以及 Google GMS 各个apk的包
Android跳转到应用商店的APP详情页面,以及 Google GMS 各个apk的包
402 0
Android开发:App点击跳转到网页的实现
在Android开发过程中,点击App里面的控件进行网页跳转是经常会遇到的需求,但是Android的网页跳转有两种方式实现App点击控件跳转到网页,第一种就是App里面的代码根据网址链接进行网页跳转,第二种就是根据Webview控件进行网页跳转。
394 0
微信分享和微信H5跳转到APP开放标签wx-open-launch-app使用及样式设置
微信分享和微信H5跳转到APP开放标签wx-open-launch-app使用及样式设置
622 0
H5跳转App、跳转小程序
H5跳转App、跳转小程序
1086 0
手机网站支付中间页跳转支付宝App支付流程
iOS篇   1. 在商户H5页面,选择支付宝支付后,会出现支付宝H5支付中间页;  2. 打开链接,跳转支付宝App进行支付;  3. 支付完成后回到发起支付方App,触发 “已完成付款” 按钮,跳转商户H5支付成功页;  Android篇   1.
3367 0
UINavigationController 自定义转场动画(模仿淘宝App跳转)
UINavigationController 自定义转场动画(模仿淘宝App跳转)
1364 0
Android WebView中跳转第三方App
一、概述 当你的应用中WebView打开一个H5页面,在这个页面中需要可以打开第三方App页面,通用的跳转方式为Scheme协议和Intent协议。
4851 0
Hybird推送通知然后跳转app
最近公司有个项目,前端使用的是react+node.js,需要增加一个推送功能,我选用了goeast作为本次推送后台,原来的友盟我尝试过,只能推送原生,混合不支持。
1371 0
+关注
菜刀文
国内第一批android开发者,具有丰富的无线架构设计经验. 对系统android底层ROM和上层应用都有较深理解.
文章
问答
视频
相关电子书
更多
千万级用户直播App——服务端架构设计和思考
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多