Intent
简介
Android中使用Intent来调用组件,Android中的组件包括Activity,Service,Broadcast Receiver,Content Provider。Android将多种理念融入到了Intent的概念中。可以使用Intent从一个应用程序中调用外部应用程序,可以使用Intent从应用程序调用内部或者外部组件,可以使用Intent触发时间,可以使用Intent发出警报等等。由上述可知,intent是具有相关数据负载的操作。
简单来说,Intent是你可以告诉Android要执行(或调用)的一种操作。Android调用的操作取决于该操作所注册的内容。
例如,编写一个Activity:BasicViewActivity
public class BasicViewActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basic_view);
}
}
basic_view布局指向了/res/layout/目录下的布局文件。我们可以在应用程序的描述文件中注册此活动,使其可以被其他应用程序调用。
注册代码如下:
<activity android:name=".BasicViewActivity"
android:label="Basic View Tests" >
<intent-filter>
<action android:name="com.zxn.intent.action.ShowBasicView" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
注册之后我们就可以使用Intent来调用此BasciViewActivity
public static void invokeBasicActivity(Activity activity) {
String actionName = "com.zxn.intent.action.ShowBasicView";
Intent intent = new Intent(actionName);
activity.startActivity(intent);
}
Android中可用的Intent
以上是我们使用Intent启动另外一个组件的过程,也是最基本的用法。我们也可以使用Intent启动Android一些自带的程序。例如:
public class IntentsUtils {
// 使用浏览器打开一个uri
public static void invokeWebBrowser(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
activity.startActivity(intent);
}
public static void invokeWebSearch(Activity activity) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.setData(Uri.parse("http://www.baidu.com"));
activity.startActivity(intent);
}
// 打开拨号界面
public static void dial(Activity activity) {
Intent intent = new Intent(Intent.ACTION_DIAL);
activity.startActivity(intent);
}
// 拨打一个电话
public static void call(Activity activity) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:904-905-5646"));
activity.startActivity(intent);
}
// 使用一个地图程序打开指定位置
public static void showMapAtLatLong(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:0,0?z=4&q=business+near+city"));
activity.startActivity(intent);
}
// 启动某个应用获取返回的数据
public static void invokePick(Activity activity) {
Intent pickIntent = new Intent(Intent.ACTION_PICK);
pickIntent.setData(Uri.parse("content://com.google.provider.NotePad/notes"));
activity.startActivityForResult(pickIntent, 1);
}
// 启动某个应用程序获取返回的数据
public static void invokeGetContent(Activity activity) {
Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
pickIntent.setType("vnd.android.cursor.item/vnd.google.note");
activity.startActivityForResult(pickIntent, 2);
}
}
创建一个简单的菜单,以便我们调用上面这些代码。如下:
public class MainActivity extends ActionBarActivity {
private final static String tag = "MainActivity";
// Initialize this in onCreateOptions
Menu myMenu = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setupButton();
this.setupEditText();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
super.onCreateOptionsMenu(menu);
this.myMenu = menu;
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
try {
handleMenus(item);
} catch (Throwable t) {
Log.d(tag, t.getMessage(), t);
throw new RuntimeException("error", t);
}
return true;
}
private void handleMenus(MenuItem item) {
this.appendMenuItemText(item);
if(item.getItemId() == R.id.menu_clear) {
this.emptyText();
} else if(item.getItemId() == R.id.menu_basic_view) {
IntentsUtils.invokeBasicActivity(this);
} else if(item.getItemId() == R.id.menu_show_browser) {
IntentsUtils.invokeWebBrowser(this);
} else if(item.getItemId() == R.id.menu_dial) {
IntentsUtils.dial(this);
} else if(item.getItemId() == R.id.menu_call) {
IntentsUtils.call(this);
} else if(item.getItemId() == R.id.menu_map) {
IntentsUtils.showMapAtLatLong(this);
} else if(item.getItemId() == R.id.menu_testPick) {
IntentsUtils.invokePick(this);
} else if(item.getItemId() == R.id.menu_testGetContent) {
IntentsUtils.invokeGetContent(this);
}
}
private TextView getTextView() {
TextView tv = (TextView)this.findViewById(R.id.textViewId);
return tv;
}
public void appendText(String text) {
TextView tv = (TextView)this.findViewById(R.id.textViewId);
tv.setText(tv.getText() + text);
}
public void appendMenuItemText(MenuItem menuItem) {
String title = menuItem.getTitle().toString();
TextView tv = (TextView)this.findViewById(R.id.textViewId);
tv.setText(tv.getText() + "\n" + title + ":" + menuItem.getItemId());
}
private void emptyText() {
TextView tv = (TextView)this.findViewById(R.id.textViewId);
tv.setText("");
}
private void dial() {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
}
private void setupButton() {
Button b = (Button)this.findViewById(R.id.button1);
b.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
parentButtonClicked(v);
}
});
}
private void parentButtonClicked(View v) {
this.appendText("\nbutton clicked");
this.dialUsingEditText();
}
private void dialWithNumber(String tel) {
String telUriString = "tel:" + tel;
Log.d(tag, telUriString);
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(telUriString));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
}
private void dialUsingEditText() {
EditText etext = (EditText)this.findViewById(R.id.editTextId);
String text = etext.getText().toString();
if(PhoneNumberUtils.isGlobalPhoneNumber(text) == true) {
dialWithNumber(text);
}
}
private EditText getEditText() {
EditText etext = (EditText)this.findViewById(R.id.editTextId);
return etext;
}
private void setupEditText() {
EditText etext = this.getEditText();
etext.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
}
protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {
super.onActivityResult(requestCode, resultCode, outputIntent);
IntentsUtils.parseResult(this, requestCode, resultCode, outputIntent);
}
}
Intent的组成
1.Intent和数据URI
public static void call(Activity activity) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:904-905-5646"));
activity.startActivity(intent);
}
以上代码中,Intent.ACTION_CALL是我们要执行的动作,打开拨号界面。下面的setData是为该Intent设置数据,这里的数据并非是真正的数据,而是指向数据的指针。数据部分是一个表示URI的字符串,这个URI包含可被推断的数据。
2.一般操作
public static void invokeWebBrowser(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
activity.startActivity(intent);
}
这个程序只是仅仅打开一个view,并没有告诉系统打开一个浏览器,Android如何知道该调用什么样的Activity来响应Intent呢?在这种情况下,Android不仅依赖于一般操作,还依赖于URI的性质。如何区分不同的data呢?这个时候就需要Intent-flater了,intent过滤器,顾名思义,就是对传递过来的intent进行过滤,从而得出我们想要的。来看看我们这个Activity所注册的描述信息:
<activity......>
<span style="white-space:pre"> </span><intent-filter>
<span style="white-space:pre"> </span><action android:name="android.intent.action.VIEW" />
<span style="white-space:pre"> </span><data android:scheme="http" />
<span style="white-space:pre"> </span><data android:scheme="https" />
<span style="white-space:pre"> </span></intent-filter>
</activity>
在intent-filter中,我们注册了一个action和data,分别对应操作和数据,action中的“android.intent.action.VIEW“在Intent文件中对应的就是ACTION_VIEW
Intent.java:
public static final String ACTION_VIEW = "android.intent.action.VIEW";
data部分我们定义了android:scheme的属性为http和https。这样intent-filter就能过滤请求为http和https的URI。
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
<intent-filter>
也可以查看单个笔记
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
<intent-filter>
3.使用extra信息
// Get the Bundle from an Intent
Bundle extraBundle = intent.getExtras();
// Place a bundle in an intent
Bundle anotherBundle = new Bundle();
// populate the bundle with key/value pairs
...
// and then set the bundle on the Intent
intent.putExtras(anotherBudnle);
我们可以使用以下方法向extra添加数据:
putExtra(String name, boolean value);
putExtra(String name, int value);
putExtra(String name, double value);
putExtra(String name, String value);
putExtra(String name, int[] values);
putExtra(String name, float[] values);
putExtra(String name, Serializable value);
putExtra(String name, Parcelable value);
putExtra(String name, Bundle value);
putExtra(String name, Intent anotherIntent);
putIntegerArrayListExtra(String name, ArrayList arrayList);
putParcelableArrayListExtra(String name, ArrayList arrayList);
putStringArrayListExtra(String name, ArrayList arrayList);
4.使用组件直接调用活动
setComponent(ComponentName name);
setClassName(String packageName, String classNameInThatPackage);
setClassName(Context context, String classNameInThatContext);
setClass(Context context, Class classObjectInThatContext);
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.andorid.contacts", "com.android.aontacts.DialContactsEntryActivity"));
startActivity(intent);
也可以直接使用类名,不构造ComponentName,例如:
Intent directIntent = new Intent(activity, BasicViewActivity.class);
activity.start(directIntent);
别忘记,在AndroidManifest.xml中注册Activity
<activity android:name=".BasicViewActivity"
android:label="Test Activity">
这里我们不需要intent-filter,因为这种类型的Intent是显式Intent,显式Intent指定了一个完全限定的Android组件,所以会忽略掉该Intent的其他部分。
5.Intent类别
<activity
<span style="white-space:pre"> </span>android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
其中android.intent.category.LAUNCHER则将这个页面定义为启动页面。
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.adCategory(Intent.CATEGORY_LAUNCHER);
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
借助于PackagerManager就可以找到与Intent相匹配的活动。
6.Intent解析规则