Android学习小结(二)——Intent
2011-03-19 13:49 onm 阅读(252) 评论(0) 编辑 收藏 举报首先介绍一下什么是Intent。Intent是连接核心组件(比如Activity)的类。官方解释为通过叫做Intent的信息来激活Activties。Intent消息是一个用于在运行时进行同一个或者不同应用组件间绑定的一个基础设施。说起来就是跳转的意思。
具体细节这个《Intents and Intent Filters》,这个《Intent》和这个《IntentFilter》这三篇官方文档已经把Intent写的非常明白了。
但是,这里面存在太多的细节和知识。
这次Android小结,主要拿我最近做的一个小Demo为例,简要说明一些牵扯到的概念,我会尽量抛弃无关的细节。
这个Demo的情境主要是OAuth验证,对于有过基于开放API的应用经验的同学肯定听说过这个词。因为本文不是对OAuth的讲解,对于不知道OAuth的同学可以自行Google。我之前的博文也曾经多次提到过,有兴趣的可以翻看。总之记住是一种“验证”就好了。
整个Demo的流程是:首先打开应用,然后判断当前用户是否已经保存了验证后的信息,如果没有验证过,则跳转到提供开放API的网站,进行验证授权,然后我们保存授权后的信息。最后,我们拿着授权后的信息进行一些具体的操作。大意如下图所示。
未验证授权:ActivityA -> WebBrowser -> ActivityB
已验证授权:ActivityA -> ActivityB
可以清楚的看到,我们需要在多个Activity之前进行切换,甚至调用不是自己写的Activity(系统自带的WebBrower)。这种操作就需要用到Intent类,之前在《Android学习小结(一)——由Activity说开去》提到过一点Intent的知识。
之前也说过Intent分为两种,一种是显式的(Explicit),另一种是隐式的(Implicit)。然而没有涉及过多,只是简要说明了显示调用的方法。
比如:
Intent i = new Intent(this, ActivityB.class); startActivity(i);
Intent的构造函数提供了多个重载,这里我用到的是public Intent (Context packageContext, Class cls)。
This provides a convenient way to create an intent that is intended to execute a hard-coded class name, rather than relying on the system to find an appropriate class for you.
这个理解起来,就是从这个Activity跳转到另一个Activity。
Intent提供了很多属性用于更改这种“意图”的细节。包括Component name,Action,Data,Category,Extras,Flags。具体细节可以参阅我前面提供的链接。这里我只说以下,对于前面我提到的这个情境需要用到的东西。
先说一下已验证授权ActivityA -> ActivityB这个流程。这个相对简单很多,没有涉及到什么技术难点,就是一个显式的Intent就可以搞定,前面写到的代码正是这个跳转,无须做多余的操作。
再说未验证授权ActivityA -> WebBrowser -> ActivityB这个流程。这个相对麻烦许多,涉及到两个难点,一是怎么从一个自定义的Activity跳转到系统的一个Activity;二是怎么能从WebBrowser跳转到ActivityB,这个相对前者又难了一步。
我们首先说从ActivityA跳转到WebBrowser。之前提到过Intent包含很多用于变更“意图”的属性,这里我们就用到了Data这个属性,我先写出完整代码,再做进一步解释。
Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(url)); startActivity(i);
你可能看到了,这次Intent的构造函数没有明确给出跳转的目标Activity。我们调用了构造函数中的另一个重载public Intent (String action)。从参数可以看出,这个实际上是设置了Intent的Action属性,什么是Action呢?官方文档这样解释:“A string naming the action to be performed.”。翻译过来大意为将要执行的操作名字的一个字符串。那么ACTION_VIEW是什么?官方文档这样解释:“Activity Action: Display the data to the user. This is the most common action performed on data.”
先放到这里,说完i.setData(Uri.parse(url))一切就明了了。
setData()方法是设置另一个Intent的属性Data。“The URI of the data to be acted on and the MIME type of that data. Different actions are paired with different kinds of data specifications.”“Similarly, if the action is ACTION_VIEW and the data field is an http: URI, the receiving activity would be called upon to download and display whatever data the URI refers to.”
也就是说当Intent的Action是ACTION_VIEW并且Data是以http:开头的URI,那么就调用浏览器显示它。很神奇吧!(但是也正是这种神奇,加重了理解整个过程的负担,使过程显得更加隐讳。虽然这样对于熟悉的人来说可能会是一种简洁的方式,但是对于向我这样的新手,理解起来还是费了不少时间。如果你喜欢Python哲学,那么没准你会讨厌它,虽然我只做了个几天的Android,但是感觉Android中存在很多这种看似巧合的神奇的东西。)
好了,说完了ActivityA -> WebBrowser的跳转,其实剩下的事情也就好办了。剩下的只有WebBrowser -> ActivityB这个过程了。如果你有认真看关于Action和View的描述,没准你已经发现了方法。
我在《Android学习小结(一)——由Activity说开去》中说过,Android的Activity的设计很像Web页面,接下来的事实更加体现了这一点。
先来回答怎么完成WebBrowser -> ActivityB这个过程,答案是就像Web页面跳转。只不过Web网页都是基于HTTP协议的,所以scheme是http。什么意思?答案还是在Action和Data中,前文说过,你给Intent的Data一个http开头的链接,它就跳转到WebBrowser了,那么我们自己定义一个scheme,让我们自己的Activity(这里是ActivityB)实现这个scheme匹配,是不是就可以了呢?答案是肯定的(而且我猜测WebBrowser的也是因为实现了scheme="http"所以才能完成这个隐式跳转的)。
方案有了,但是我们还缺少一个至关重要的东西,怎么让Activity实现这个scheme(其实说“实现”这个词不是很好,说成匹配较好,就像我之前说的,这个东西就像正则匹配URL一样)。方法是intent-filter。
Structured description of Intent values to be matched. An IntentFilter can match against actions, categories, and data (either via its type, scheme, and/or path) in an Intent. It also includes a "priority" value which is used to order multiple matching filters.
intent-filter我不细说了,就直接说实现。方法为在AndroidManifest.xml中声明的ActivityB添加相应的intent-filter属性,action为android.intent.action.VIEW,data为android:scheme="myscheme"。这样通过让浏览器,访问myscheme://xxxx的链接,webbrowser就会自动切换到ActivityB了。
于是大工告成!但是还不能高兴的太早,这里有一个小问题,就是当你跳到ActivityB后,按手机上的Back键,会回到WebBrowser,然而WebBrowser只是个中间过程,我们肯定不希望看到WebBrowser。
对于这个问题,我也一直没有什么解决方案,只好求助StackOverflow,最终得以解决(这里我不免再次推荐一次StackOverflow,我多次表达过我对这个网站的喜爱之情,如果你知道网站的“作者”,那么你会更喜欢它)。我粘一下问题的链接,有兴趣的同学,自己前去看看吧!
注:本人初学,可能一些细节上会有纰漏,如果你有什么迷惑可以留言或者可以Google,谢谢!