原创微信公众号郭霖 WeChat ID: guolin_blog
有些人可能会说了,隐式启动活动不是很简单吗?这有什么不理解的?话先别说的这么早,对于隐式启动,还是具有很大的坑要爬的,当然,您如果是一个资深开发者就另当别论了。
本篇文章,我们从最简单的开始,一步步引入,相信这样的方式,读起来也会轻松一些。
我们平时启动一个活动,会通过两种方式。1、显示启动;2、隐式启动。
首先,我们来看两个很简单的小案例(实现打电话)
我们在布局文件提供一个 TextView 用于提示输入电话号码,在 EditText 里面输入号码,点击按钮的同时,获取到用户输入的号码,并且启动打电话功能。
主活动代码很简单,MainActivity:
运行后如下:
这个简直太简单了,估计代码都能烂肚子里了。
嗯,的确很简单,那就紧跟脚步,我们继续看一个简单的自定义启动活动的代码。
自定义Activity,并隐式方式启动
我们都知道,如果要想自定义隐式启动别的 activity,需要给该 Activity 添加“意图过滤器”。
通过在 标签下配置 的内容,可以指定当前活动能够响应的 action
和 category,打开 AndroidManifest.xml,添加如下代码:
在 标签中我们指明了当前活动可以响应com.itydl这个 action,我们可以随便写里面的内容,它的加入表示给我们的 Activity 添加一个动作,只有带动作的 Activity 才能被隐式启动。
而 标签则包含了一些附加信息,更精确地指明了当前的活动能够响应的 Intent 中还可能带有的 category。意图中设置的 action 必须跟 "com.itydl" 是完全匹配的,只有 和 中的内容同时能够匹配上 Intent 中指定的 action 和 category时,这个活动才能响应该 Intent。
我们也道,android.intent.category.DEFAULT 是一种默认的 category,在调用 startActivity() 方法的时候会自动将这 category 添加到 Intent 中(查看所有系统源码,也都带上了这个 category,我们也无需多去关心 category 它可能存在的坑了)。
对于Action的原理是:当 startActivity() 运行的时候,该Activity会去系统所有清单文件中找对应的 Action("") 里面能匹配的 Activity,找有没有对应的 action 与我们所写入的能匹配的,如果有(这里是 NextActivity),这样就启动了 NextActivity。
既然,NextActivity 有了动作,那么我们的 MainActivity 再添加一个按钮,使用隐式方式启动它。如下:
此时运行程序,发现能够正常启动。我们发现第一个例子启动打电话功能时候,还添加了一个setData()。那么,我们自定义的也可以同样添加data。修改清单文件 NextActivity 配置代码如下:
这个时候,我们再运行程序,发现程序崩溃。这是因为我们隐式启动代码中,并没有完全跟清单文件中 下面的内容匹配。要想匹配成功,我们也要去代码中设置data。再回到小案例一中,我们也就知道了为什么启动打电话功能要设置 setData 了,还不是因为电话清单文件源码中有这个 data 标签吗。
在这里浅显介绍一下系统添加 data 下面的标签都有哪些。标签中主要可以配置以下内容:
1. android:scheme
用于指定数据的协议部分。
2. android:host
用于指定数据的主机名部分。
3. android:port
用于指定数据的端口部分,一般紧随在主机名之后。
4. android:path
用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
5. android:mimeType
用于指定可以处理的数据类型,允许使用通配符的方式进行指定。只有标签中指定的内容和 Intent 中携带的 Data 完全一致时,当前活动才能够响应该 Intent。不过一般在标签中都不会指定过多的内容,常见的是 mimeType 和 scheme。
给我们的隐式启动按钮加入如下代码:
intent.setData(Uri.parse("ydl:qwe"));
运行程序不再报错。
上边的内容,对于一个初学者来说是必须掌握的内容。那么再来看看一些细节问题,这些细节问题不知道,可能还真会让你不知道如何去隐式启动别的Activity!
深入分析隐式启动的细节
首先先从自定义隐式启动开始讨论。上边代码 Uri.parse() 参数内容"ydl:qwe"。我们看到 qwe 好像很别扭,其实 setData 的英文名称就告诉我们设置数据的了。基于上面对系统里面配置介绍,我们清单文件中是android:scheme,这是一个协议,因而我们设置数据必须要以scheme后边内容开头。这里是 "ydl" 作为了协议。而后面 "qwe" 内容可以随便写。例如我改成如下代码:
intent.setData(Uri.parse("ydl:234"));
仍然可以启动下一个活动。
那么我们再回到最初的小案例,有如下代码:
intent.setData(Uri.parse("tel:"+phone));
这里不就是一个协议吗?在清单文件中对应的 Activity 肯定有这个协议,我们就去上层源码看一看,找到如下代码:
我们看到 android:permission 就是我们打电话要指定的权限。而往下看第一个intent-filter
action android:name="android.intent.action.CALL" /> 不就是针对我们代码中要设置的Action(intent.setAction(Intent.ACTION_CALL);)吗?
到了这里,相信这个细节大家都能掌握了。那么接着往下继续爬坑~
我们发现,打电话OutgoingCallBroadcaster的清单文件中有太多的 intent-filter,看花了眼,我们到底怎么知道匹配哪个 intent-filter 才能启动打电话这个活动呢?其实,原理很简单,在清单文件中的 intent-filter 代表我们可以有好几种启动方式好几种写法去启动这个打电话这个活动。我们使用哪一种方式都无所谓的,都可以。那么我们模仿这种情况,来对自定义启动活动也这么添加几个 intent-filter,看完下面的内容,这些坑也就爬完了。
模仿源码为自己的活动配置不同的intent-filter
首先我们在清单文件中继续添加intent-filter
此时两个intent-filter,我们为了验证刚才的说法,把启动活动的代码修改一下:
我们发现都改成了ydl2,这样启动时匹配的是上边这个 intent-filter。能正常启动活动。
注意:启动活动代码必须与某一个 intent-filter 相匹配才能正常启动活动,否则会报错。这是为什么,相信我们很简单就能理解原因了。
继续跟进:
我们在清单文件中除了可以配置多个 intent-filter,还可以配置多个 data,以及多个 action 吗?(很多源码中也是这样的)。我们再把清单文件中代码作如下修改来试试:
这里添加了多个 data 多个 action,其实,在我们在启动活动的代码位置,只需要配置任意一条 data 以及任意一条 action 就可以成功启动这个 activity 了,不需要全部匹配。活动代码即使这么写,也是没有任何问题:
启动活动成功。
最后,还有一点点就完结了。即常见的android:mimeType这个属性。
我们知道了,data 是用来传递数据的,通过 setData 把数据放进里面,会把数据传递给目标Activity,在目标Activity可以通过 getIntent()(获取启动这个activity的意图对象)方式来获取里面的数据。而 android:mimeType 是用来定义你 setData 用来传递什么数据类型的。例如,一般我们传递文本数据,我们就可以这么写:
我们首先测试只有 android:mimeType 的时候。
当android:mimeType和android:scheme同时存在的时候。我们需要注意:如果代码先设置 setData(),后 setType() 后者会把前者清理掉,反之亦然,这里就跟你女神问你“你妈和我掉水里你先救谁”原理是一样的。
我们需要通过setDataAndType()方法,把 scheme 和 mimeType 同时设置进去才能匹配对应的清单文件中的 intent-filter。例如我清单文件中代码是:
那么我们启动的时候,需要通过:
intent.setDataAndType(Uri.parse("ydl2:qwe"),"text/username");
这样就能完好匹配清单文件内容,可以正常启动activity了。
终于写完了,相信看完此篇文章你对隐式启动活动的原理更加清晰了。以后启动任何互动,只需要看看那个活动的清单文件内容,就能轻松通过隐式启动的方式去打开它了!
最后,点击下方阅读原文可以跳转到作者的博客来阅读本文章哦!
完。。。。。。。。。。。。。。。。。。。。。
文章原创作者GuoLin 书籍推荐
郭林大神原创android 书籍:《第一行代码 android》
网友评论