真的需要new一个Intent吗?

在Android中,打开一个Activity,有多少种方式?不过不管是使用什么方式,最终都没办法逃避创建一个Intent,然后startActivity。

那么,如果想根据数据来确定跳转的页面呢?需要怎么做比较好一点。DeepLink好像是一个不错的解决方案,在AndroidManifest.xml中,定义好data字段,标记好scheme、host等等,然后按照规则进行传递,这样也可以跳转到某些页面。

但是,这样真的方便吗?我们需要在每个需要跳转的Activity上,设定好data?当然,现在Github上也有一些成熟的Deeplink的解决方案,只需要在为某个Activity设定data,然后所有deeplink的链接都跳转到这个Activity上,最后再由这个RouterActivity,去决定向那里跳转,并携带上参数。

那么还有别的方案吗?

Intent的toUri()

直到我发现Intent居然有个toUri()的方法,我就觉得有办法对Intent进行简单的序列化了。

从文档中可以看出,toUri()方法可以将一个Intent转换成一个URI,其中包含了action、categories、flags等一些必要的参数。

那么文章开头的地方,那么startActivity,最终转换成URI,是什么呢?

仔细看,flag、compoent、putExtra的数据,都被序列化成一个字符串了。

得到的这个Uri,如何使用呢?可以借助Intent的一个静态方法,parseUri()将一个Intent的URI,转换成实际的Intent对象。

这样的话,其实下面的方式,同样也会调起TwoActivity,并且带过去一个balabala的ID数据。

到这里,基本上把本篇文章需要讲解的内容都讲明白了。但是有追求的程序员,我们还是要深挖一下,toUri()到底干了些什么?

toUri()到底干了什么?

来看看toUri()的具体实现。

从源码的实现看,其实toUri只是把每个字段读取出来,然后按照规则进行序列化,最后parseUri()只是按照这个规则进行了反序列化。熟练的话,基本上无需使用toUri这个方法转换,就可以盲写Intent的URI。

会有什么隐患吗?

我们使用的API都是官方对Intent提供的,用起来好像也确实没有什么问题。但是真的像看上去那么美好吗?

从传递参数的方向看,toUriInner()方法是toUri()方法中,对传递的数据进行序列化的方法。下面看看具体实现。

可以看到,toUriInner()方法,它对基本的数据类型,都有对应的类型进行转换,例如之前S.id=balabala表示一个key为id的String类型的值balabala。

好像已经涵盖了所有的类型传参了,可是并不是这么美好。发现没有,没有关于Bundle的参数传递,难道是看漏了吗?

代码也不看了,做个试验验证一下。

看看Log输出:

可以看到,toUri()这个方法,确实对Bundle参数的序列化并没有做特殊处理。

得到的结论,就是虽然toUri和parseUri方法确实很好用,但是也是有缺陷的,Bundle传递的数据没法序列化成Uri。实际使用中,就需要我们对传递的参数有严格的要求,避免使用Bundle去传递数据。

结语

这样就可以简单的对Intent进行传递,可以从后端服务器拿到一个IntentUri,这样就无需给每个点击设定好既定的打开页面了。当然,怎么用还是要看实际的使用场景了。

03-05 21:03