丰富的线上&线下活动,深入探索云世界
做任务,得社区积分和周边
最真实的开发者用云体验
让每位学生受益于普惠算力
让创作激发创新
资深技术专家手把手带教
遇见技术追梦人
技术交流,直击现场
海量开发者使用工具、手册,免费下载
极速、全面、稳定、安全的开源镜像
开发手册、白皮书、案例集等实战精华
为开发者定制的Chrome浏览器插件
本节书摘来自异步社区《Android应用案例开发大全(第二版)》一书中的第6章,第6.6节Android源代码与过滤器,作者李宁,更多章节内容可以访问云栖社区“异步社区”公众号查看
6.6Android源代码与过滤器Android开发权威指南(第二版)第X问1源代码目录:src/ch06/AndroidSrcFilter
6.6.1系统内置程序有哪些窗口可以利用到现在为止已经可以使用多种方式调用另一个应用程序的窗口了,但可能很多读者一直有一个疑问,如果是调用其他应用程序(不是自己编写的程序)中的窗口,又是如何得知这些程序中哪些窗口提供了Action,哪些窗口可以通过显式方式调用呢?这些问题的答案将在本节和下一节为读者揭晓。
尽管Intent类中定义了用于调用系统窗口的常量,但并没有为全部的Action定义常量,而且可能有一些解释不太清楚,所以需要采用下面的方法获取更详细的信息。
Android系统内置应用程序的源代码都放在了如下的目录:
/packages/apps每一个应用以一个单独的目录存放,例如,下面是一些常用内置应用的目录。
6.6.2显示计算器(Calculator)计算器是笔者最喜欢的一个程序,因为Calculator可能是唯一没有使用AndroidSDK内部API的程序,也就意味着Calculator可以单独提出来作为独立的第三方程序,并通过常规的方法安装到系统中。
对于很多初学者来说,由于并没有在Intent类中找到带Calculator的ActivityAction,可能第一反应是系统不允许调用Calculator。不过在这里可以肯定地告诉大家,系统中所有带UI的内置程序都允许调用相应的窗口,只是有的Action或Category不太好找罢了。
可能通常认为android.intent.action.MAIN是给系统用的,与第三方程序无关。实际上,该Action不仅系统可以调用,第三方程序同样也可以调用。后面定义的3个Category指定一个就可以,不过指定前两个,系统中肯定有重复的定义。所以通常使用下面的代码调用Calculator。
publicvoidonClick_Calculator(Viewview){Intentintent=newIntent("**android.intent.action.MAIN**");intent.addCategory("**android.intent.category.APP_CALCULATOR**");startActivity(intent);}当然,android.intent.action.MAIN和android.intent.category.APP_CALCULATOR在Intent类中已经定义了,所以也可以使用下面的代码调用Calculator。Intentintent=newIntent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_APP_CALCULATOR);startActivity(intent);如果Intent类中已经为某些Action和Category定义了常量,应尽量使用这些常量,而不要直接使用字符串形式的Action和Category。因为如果应用程序中的相应Action和Category改变,可能会影响窗口的调用者,尽管发生这种情况的可能性并不大。在不知道具体的Action或Category定义的常量名的情况下,可以通过查看Android源代码获取相应的字符串形式的Action和Category,然后在Eclipse中跟踪进Intent类,并查找这些字符串,这样就可以很容易找到相应的常量。例如,Intent.ACTION_MAIN和Intent.CATEGORY_APP_CALCULATOR的定义代码如下:
注意
6.6.3用浏览器(Browser)显示网页在5.7.4小节曾使用下面的代码调用浏览器显示指定的页面。
Intentintent=newIntent("android.intent.action.MAIN");intent.addCategory(Intent.CATEGORY_BROWSABLE);//Intent.CATEGORY_APP_BROWSER是android.intent.category.APP_BROWSER对应的常量intent.addCategory(Intent.CATEGORY_APP_BROWSER);startActivity(intent);但要注意最好不要单独只用其中一个Category,否则可能会有多个过滤器满足过滤条件,这就有可能显示选择列表了。例如,只指定Intent.CATEGORY_BROWSABLE,可能会显示如图6-9所示的选择列表。可以看到,Browser、People和Phone程序中都有窗口满足过滤条件。
答疑解惑:为什么显式调用浏览器会导致Uri无效
在6.4节中曾在InvokeOtherActivity程序中使用显式的方式调用了WebBrowser中的主窗口用于显示指定的网页,在这个例子中程序可以完美地运行。但如果我们使用这种方法显式调用系统内置的浏览器会发现,尽管浏览器可以成功调用,但往里传入的Uri却无效了。究其原因是因为在我们实现的WebBrowser程序的主窗口类的onCreate方法中不管三七二十一都从Intent.getData方法中获取了Uri,所以无论何种情况,只要主窗口成功显示,就一定会获取传入的Uri。而系统内置的浏览器对Action进行了验证。只有在Action和Category符合要求的情况下才会继续读取Data中的数据。
系统浏览器在启动时会通过Intent.getAction方法返回一个Action,如果要让该方法返回非空值,必须使用下面两种方法调用窗口。>
隐式调用窗口。单击程序图标启动程序。第1种情况就不需要多讲了,因为已经为窗口指定了一个Action,Intent.getAction方法返回的就是这个Action。而第2种情况Intent.getAction方法返回了android.intent.action.MAIN。读者可以在onCreate方法中加入如下的代码,看看在启动程序时是否会在LogCat视图输出这个Action。
if(getIntent().getAction()!=null)Log.d("action",getIntent().getAction());如果直接使用显式方法调用窗口,Intent.getAction方法会返回null。而从本节前面给出的过滤器代码可知,要处理Uri,Action必须是android.intent.action.VIEW。所以如果显式调用浏览器的BrowserActivity窗口,根本不可能通过Action检测,因此当然不会执行到接收Uri的代码了,这也是为什么显式调用系统浏览器显示网页后,Uri会被忽略的原因。
IntentcallIntent=newIntent(Intent.ACTION_CALL,Uri.parse("tel:12345678"));startActivity(callIntent);其中Intent.ACTION_CALL的值是android.intent.action.CALL。现在来研究一下具体哪个程序中的哪个窗口来响应上面代码的请求。