今天,我们来研究一下Intent,没错,就是前面说过的比较难理解的那个东西,希望通过这篇文章之后,你发现前面那句话其实是不对的。
前文中说过,Intent就像Activity之间的双面胶,就字面意思而言:“意图, 意向, 目的”, 基本上可以诠释这个对象的作用。它里面包含的就是一些信息,这些信息能够告诉我们当前发生了什么,以及想要干什么。我觉得和前面的事件驱动中的事件非常 像,不同的是,它不仅仅包含事件,还包含一些数据信息。Intent或者也可以说像一个需求说明一样,说明了当前的事件以及一些数据,接下 来,Android会依据这个Intent的说明,为其找到一个Activity,并把这个Intent交给这个Activity。看起来Intent好 像是征婚广告一样哦,Intent提出自己的一些描述(不同的是,他描述的是自己,而不是描述的别人),然后Android根据这些描述找到何时的 Activity。
Intent有两种,一种是显式Intent,另一种是隐式Intent。显式Intent会在自己的说明中直接声明由谁(哪个Activity)来接收 处理这个Intent。显式的Intent是说,我已经有了意中人了,告诉Android不用费劲找了,可以直接定位到意中人,例如前文中的这个例子:
Intent intent = new Intent();
intent.putExtra("name", editText.getText().toString());
intent.setClass(ActivityLifecycle.this, AlertDialog.class);
通过setClass方法,直接告诉Android,此Intent交由AlertDialog处理。也可以通过setComponent()、setClassName()等方法来做同样的事情。
在一般的程序中, 我觉得使用显式Intent已经足够了。这样程序看起来简单易懂,毕竟大多数的Android程序都不会有太复杂的Activity之间的关系。
在前文中的另外一个方法中,使用的就是隐式的Intent。隐式Intent呢,比较含蓄,比较糊涂,比较模糊,还没有明确的目标,并且比较悲观,不会对对方提一些要求,只是描述了一下自己的情况,意思就是说,我就是我所描述的这样的一个人,谁能接受, 谁就可以应征。:)
Intent intent = new Intent();
intent.putExtra("name", editText.getText().toString());
intent.setAction("com.roiding.sample.action.MAIN");
Intent说明自己的方式有:
action 用来指明执行的动作,比如说ACTION_VIEW, ACTION_EDIT, ACTION_MAIN,这都是在Android中定义的标准action,开发者可以自己定义自己需要的action,用字符串来表示。更多标准 action参看这里。
category 描述action的附加信息,这个属性我一直不太明白,它被设计出来的用意到底是为什么,到目前为止,我对他的理解是:它就像一个action类别,例 如:CATEGORY_LAUNCHER、CATEGORY_ALTERNATIVE。属于CATEGORY_LAUNCHER这个类别的,可以被 Android放到顶级列表(类似于九宫格的那个界面)中被执行,属于CATEGORY_DEFAULT这个类别的,可以用 startActivity(intent)来启动Activity,等等。而这些行为都是Android内定的,所以自定义category不知道会有 什么意义,更多标准category参看这里。
data 动作操作的数据,这部分数据会像嫁妆一样,携带给接收它的Activity,Uri格式。Uri的概念和传统的URI的概念是一致的,遵循RFC 2396。 而Uri最终是由ContentProvider提供的,所以会涉及到ContentProvider的概念,这里也暂时不去解释了,只需要知道这个 data所声明的数据,就像一个url一样,通过这个url,可以找到提供这个url的ContentProvider提供的数据,然后就可以操作这些数据了。这里面的data似乎和前面的extras功能有重叠?按照我的理解,data确实可以放到extras中传递,但是单独把它提出来确有它的用意。在后面的IntentFilter中会有交代。
既然已经比喻为征婚广告了,把Intent比喻为征婚的需求,那么由Android系统根据什么挑选的候选人呢?
前面中说过这个文件:AndroidManifest.xml,而且当时将其比喻为户口簿,这下好了,所有的适龄青年(Activity)都在这个大的户口簿上了,按照Intent的需求直接在户口簿中寻找就可以了。那又是如何知道哪个适龄青年是否符合要求呢?
在AndroidManifest文件中,对每个适龄青年(Activity)都做了说明,就是intent-filter,它说明了当前这个适龄青年愿意接收什么样的需求,这样当Intent与这个Intent-filter中的说明一致时,Intent就找到了Activity。
这样,当一个Intent的所有说明,都被Activity的intent-filter接受时,这个Activity就是候选人之一。如果有多个 Activity成为候选人,那么在程序运行的时候Android提示你从多个Activity中手动选择一个来作为最终的intent接收执行者。
对于Activity来说,在它的intent-filter中,可以有多个action,多个category,多个data,这样可以有多个Intent可以与之匹配。
说到这里,前面的那个关于data和extras功能重叠的问题似乎还没有解决,所以这个data的重要的作用就是,它提供了一种反向挑选的机制,使 Activity对Intent也可以提出要求,要求Intent的data必须是intent-filter中声明的data中之一(因为可以有多个 data)。这点是非常重要的,不然又会出现ActivityNotFoundException之类的错误了。
到此篇文章为止,一般的Android界面编程应该已经够用了,而对于ContentProvider、Adapter、Services等,在一般的应用中,可以完全不用考虑。等到必须要使用的时候再说吧。
前面的文章已经讲到了如何在一个Activity中与用户进行交互。这篇文章将解释如何创建多个Activity的用户界面,以及了解Activity的生命周期。这次是一个完整的示例,可以在这里下载源代码。
这个多Activity的示例程序的功能大概是这样的:
在主页面上有三个元素:一个文本输入框,两个按钮。用户可以在文本框中输入一些字符
点击第一个按钮,将弹出一个对话框形式的Activity,显示”Hello, …”
如果点击的是第二个按钮,将显示另一个全屏的Activity,显示”Hello, …”
OK,按照前面的规矩,分成几步:
第1步,先完成UI的设计,创建布局。
从程序来看,似乎有三个Activity,但是第二个和第三个几乎是相同的,于是,只创建两个布局:
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<EditText
android:id="@+id/edittext_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/button_sayhello_dialog"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_dialog"
/>
<Button
android:id="@+id/button_sayhello_activity"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_activity"
/>
</LinearLayout>
res/layout/dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/textview_hello"
android:text="@string/hello"
/>
第2步,然后呢,需要把上面提到的字符变量声明一下:
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello, </string>
<string name="hello_dialog">Say Hello(Dialog)</string>
<string name="hello_activity">Say Hello(Activity)</string>
<string name="app_name">Activity Lifecycle</string>
</resources>
通过前面的文章,上面的东西应该都比较好懂。
第3步,创建Activity,这里和第一步一样,虽然有三个Activity,但是看起来用两个其实就够了。然而事实并非如此,具体原因后续,我们需要定义三个Activity:分别将他们定义为:ActivityLifecycle(用来显示主画面)、AlertDialog(用来显示对话框)和AlertActivity(用来显示那个全屏的Activity)。
主Activity:
package com.roiding.sample;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class ActivityLifecycle extends Activity {
private static final String TAG = "ActivityLifecycle";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate …");
setContentView(R.layout.main);
final EditText editText = (EditText) findViewById(R.id.edittext_input);
// try to display a dialog
Button [...]
Recent Comments