Android的应用程序框架允许您创建丰富和创新应用使用一组可重用的组件。本篇解释如何构建的组件定义应用程序的构建块,并使用意图如何连接在一起。
- Intents and Intent Filters
- Activities
- Services
- Content Providers
- App Widgets
- Processes and Threads
Intent Type可分为显式意图(Explicit intents)和隐式意图(Implicit intents),下图所示。描述一个隐含的意图是通过系统启动另一个活动:[1]活动创建一个意图的行动描述并将其传递给startActivity()。[2]的Android系统搜索所有应用程序意图过滤器匹配的意图。当找到匹配,[3]系统开始匹配的活动(活动B)通过调用itsonCreate()方法并传递它的意图。警告:确保你的应用程序是安全的,开始时总是使用一个显式意图服务,不为你的服务声明意图过滤器。使用隐式意图启动一个服务是一个安全隐患,因为你无法确定服务响应的目的,和用户不能看到哪些服务开始。
在某些时候比如调用系统相册传入action,就可以调出系统相册,当然也可以自定义Action,例如
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
activity的启动通过startActivityForResult时,需要声明Action:CATEGORY_DEFAULT,用于意图过滤。
<activity android:name="TestActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
一个应用有多少个Context对象?这个问题其实很简单。Application、Activity和Service从继承关系来看,最终父类是Context,我们可以这样认为:每个Activity都是一个Context,每一个Service都是一个Context,而Application也是一个Context。每个应用自启动都会创建一个Application,如果应用内有自定义Application那么在清单文件manifest里面需要声明,Activity和Service同样需要。
在开发中调用系统服务,通过Action过滤,例如调用系统的闹钟,只需要传入ACTION_SET_ALARM即可,实例代码如下:
public void createAlarm(String message, int hour, int minutes) {
Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
.putExtra(AlarmClock.EXTRA_MESSAGE, message)
.putExtra(AlarmClock.EXTRA_HOUR, hour)
.putExtra(AlarmClock.EXTRA_MINUTES, minutes);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
调用系统服务需要更具功能请求相应的权限,以设置闹钟为例,权限如下:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
下面是一些列的系统功能调用代码块,先来看倒计时,在(Android 4.4)
public void startTimer(String message, int seconds) {
Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
.putExtra(AlarmClock.EXTRA_MESSAGE, message)
.putExtra(AlarmClock.EXTRA_LENGTH, seconds)
.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
在日历上添加事件,实例和意图过滤如下:
public void addEvent(String title, String location, Calendar begin, Calendar end) {
Intent intent = new Intent(Intent.ACTION_INSERT)
.setData(Events.CONTENT_URI)
.putExtra(Events.TITLE, title)
.putExtra(Events.EVENT_LOCATION, location)
.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin)
.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
<activity ...>
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<data android:mimeType="vnd.android.cursor.dir/event" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
调用系统Camera
static final int REQUEST_IMAGE_CAPTURE = 1;
static final Uri mLocationForPhotos;
public void capturePhoto(String targetFilename) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.withAppendedPath(mLocationForPhotos, targetFilename);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bitmap thumbnail = data.getParcelable("data");
// Do other work with full size photo saved in mLocationForPhotos
...
}
}
读取联系人(READ_CONTACTS)
static final int REQUEST_SELECT_CONTACT = 1;
public void selectContact() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_SELECT_CONTACT);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_SELECT_CONTACT && resultCode == RESULT_OK) {
Uri contactUri = data.getData();
// Do something with the selected contact at contactUri
...
}
}
查询联系人信息
static final int REQUEST_SELECT_PHONE_NUMBER = 1;
public void selectContact() {
// Start an activity for the user to pick a phone number from contacts
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(CommonDataKinds.Phone.CONTENT_TYPE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_SELECT_PHONE_NUMBER);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_SELECT_PHONE_NUMBER && resultCode == RESULT_OK) {
// Get the URI and query the content provider for the phone number
Uri contactUri = data.getData();
String[] projection = new String[]{CommonDataKinds.Phone.NUMBER};
Cursor cursor = getContentResolver().query(contactUri, projection,
null, null, null);
// If the cursor returned is valid, get the phone number
if (cursor != null && cursor.moveToFirst()) {
int numberIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER);
String number = cursor.getString(numberIndex);
// Do something with the phone number
...
}
}
}
诸如此类方法块太多就不一一列举。Android系统设置的功能模块的打开方法,除了通过manager实现,也可以通过intent传递意图打开,代码如下:
public void openWifiSettings() {
Intent intent = new Intent(Intent.ACTION_WIFI_SETTINGS);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
ACTION:ACTION_SETTINGS
ACTION_WIRELESS_SETTINGS
ACTION_AIRPLANE_MODE_SETTINGS
ACTION_WIFI_SETTINGS
ACTION_APN_SETTINGS
ACTION_BLUETOOTH_SETTINGS
ACTION_DATE_SETTINGS
ACTION_LOCALE_SETTINGS
ACTION_INPUT_METHOD_SETTINGS
ACTION_DISPLAY_SETTINGS
ACTION_SECURITY_SETTINGS
ACTION_LOCATION_SOURCE_SETTINGS
ACTION_INTERNAL_STORAGE_SETTINGS
ACTION_MEMORY_CARD_SETTINGS