我要15天消化掉Android官方API指南--第四天

今天全国大范围有雨,我也连续扯了三天,今天屯干货。

  • Intent是个好东西,我申请专利的软件产品,当时为了加速申请,写的代码很潦草。忘记了解决Activity生命周期,还好鄙人逻辑思维不差,要不然跳来跳去,非疯掉不可。这个图片大家随意看看就好,不用记,踩过一次坑,保证你终身难忘。编程有啥可背东西吗?你疯狂的踩坑,疯狂的积累,倒逼自己长脑子,长见识,岂不是人生乐事(我疯了,哈哈,别理我)
  • 上面提到Activity直接的切换可以调用startActivity实现,而且这货可以带数据过去,带数据的时候,要调用startActivityForResult(),这方法你直接翻译就好了,不扯多了,这里分开说,只讲Intent。
  • 四大组件我都知道,Service是唯一一个不使用用户界面,在后台吃流量的鬼。你要开启一个服务,跟上面一样,不过方法是startService(),Intent是要提供启动服务的描述,就像你在Activity之间做跳转(显式Intent)的时候,总得提供两个Activity吧。注意啊,不管你调用了多少次startService(),一次stopService(Intent)就足够了,不要手欠。
boolean bindService (Intent service, 
                ServiceConnection conn, 
                int flags)

看好这个代码,bindService()是布尔型的,还有里面的三个参数都是啥,绑定服务的时候,请参照:当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

  • 广播是我玩的最少的组件,但我还是做过一个Demo,是一个静态广播和Toast组合实现的开机启动问候,不过有的手机并不能实现,毕竟用户未必喜欢的,就是各大手机厂商所抵触的。广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将 Intent 传递给 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将广播传递给其他应用。
void sendStickyOrderedBroadcast (Intent intent, 
                BroadcastReceiver resultReceiver, 
                Handler scheduler, 
                int initialCode, 
                String initialData, 
                Bundle initialExtras)

这个方法很有意思,粘性有序广播,API21 的时候因为安全性的问题被打入冷宫,我一开始不知道,放在这儿碍碍眼。


早听说Intent有两种类型,显式和隐式。

  • 显式 Intent:按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
  • 隐式 Intent :不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
  • 显式Intent不难理解,来说说隐式把,假如你手机上下载过几款不一样的美颜相机(B612),或者几个不同浏览器时,如果你从一款应用调用了相机,就会有弹窗,询问你选择原生相机,还是其他。或者你写的程序用到了WebView的话,就会有个对话框问你选择自带浏览器还是其他。这就是隐式Intent的表现形式。人家官文是这么说的,感受下:创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并向其传递 Intent 对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。也是为了确保安全性问题,API21以后,隐式调用bindService(),程序报错。
  • 当你想指定要启动的组件,请切记写上要启动的组件名称。启动 Service 时,您应始终指定组件名称。 否则,您无法确定哪项服务会响应 Intent,且用户无法看到哪项服务已启动。
  • Intent 的这一字段是一个 ComponentName 对象,您可以使用目标组件的完全限定类名指定此对象,其中包括应用的软件包名称。 例如, com.example.ExampleActivity。您可以使用 setComponent()、setClass()、setClassName() 或 Intent 构造函数设置组件名称。
  • 可以使用各种 putExtra() 方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras() 将Bundle 插入 Intent 中。
  • 显式Intent官方示例:
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
  • 用户可能没有任何应用处理您发送到 startActivity() 的隐式 Intent。如果出现这种情况,则调用将会失败,且应用会崩溃。要验证 Activity 是否会接收 Intent,请对 Intent 对象调用 resolveActivity()。如果结果为非空,则至少有一个应用能够处理该 Intent,且可以安全调用 startActivity()。 如果结果为空,则不应使用该 Intent。如有可能,您应停用发出该 Intent 的功能。、
// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

调用 startActivity() 时,系统将检查已安装的所有应用,确定哪些应用能够处理这种 Intent(即:含 ACTION_SEND 操作并携带“text/plain”数据的 Intent )。 如果只有一个应用能够处理,则该应用将立即打开并为其提供 Intent。 如果多个 Activity 接受 Intent,则系统将显示一个对话框,使用户能够选取要使用的应用。

  • 如果有多个应用响应隐式 Intent,则用户可以选择要使用的应用,并将其设置为该操作的默认选项。 如果用户可能希望今后一直使用相同的应用执行某项操作(例如,打开网页时,用户往往倾向于仅使用一种网络浏览器),则这一点十分有用。

但是,如果多个应用可以响应 Intent,且用户可能希望每次使用不同的应用,则应采用显式方式显示选择器对话框。 选择器对话框每次都会要求用户选择用于操作的应用(用户无法为该操作选择默认应用)。 例如,当应用使用 ACTION_SEND 操作执行“共享”时,用户根据目前的状况可能需要使用另一不同的应用,因此应当始终使用选择器对话框,如图 2 中所示。

要显示选择器,请使用 createChooser() 创建 Intent,并将其传递给 startActivity()。例如:

Intent sendIntent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

这将显示一个对话框,其中有响应传递给 createChooser() 方法的 Intent 的应用列表,并且将提供的文本用作对话框标题。

  • 要公布应用可以接收哪些隐式 Intent,请在清单文件中使用<intent-filter> 元素为每个应用组件声明一个或多个 Intent 过滤器。每个 Intent 过滤器均根据 Intent 的操作、数据和类别指定自身接受的 Intent 类型。 仅当隐式 Intent 可以通过 Intent 过滤器之一传递时,系统才会将该 Intent 传递给应用组件。
    -为了接收隐式 Intent,必须将 CATEGORY_DEFAULT 类别包括在 Intent 过滤器中。 方法 startActivity() 和 startActivityForResult() 将按照已申明 CATEGORY_DEFAULT 类别的方式处理所有 Intent。 如果未在 Intent 过滤器中声明此类别,则隐式 Intent 不会解析为您的 Activity。例如,以下是一个使用包含 Intent 过滤器的 Activity 声明,当数据类型为文本时,系统将接收 ACTION_SEND Intent :
<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>
  • 为了更好地了解一些 Intent 过滤器的行为,我们一起来看看从社交共享应用的清单文件中截取的以下片段。
<activity android:name="MainActivity">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>
  • PendingIntent 对象是 Intent 对象的包装器。PendingIntent 的主要目的是授权外部应用使用包含的 Intent,就像是它从您应用本身的进程中执行的一样。

接下来说说,能与Intent勾搭上的系统应用,既然是勾搭,那就是隐式Intent对象中执行相关操作。就像我上面举的例子,当调用 startActivity() 或 startActivityForResult() 并向其传递隐式 Intent 时,系统会 将 Intent 解析为可处理该 Intent 的应用并启动其对应的 Activity。 如果有多个应用可处理 Intent,系统会为用户显示一个对话框,供其选择要使用的应用。有一点需要严重注意的:如果设备上没有可接收隐式 Intent 的应用,您的应用将在调用 startActivity() 时崩溃。如需事先验证是否存在可接收 Intent 的应用,请对 Intent 对象调用 resolveActivity()。如果结果为非空,则至少有一个应用能够处理该 Intent,并且可以安全调用 startActivity()。 如果结果为空,则您不应使用该 Intent。如有可能,您应停用调用该 Intent 的功能。

public class MainActivity extends Activity {

    private static final Uri ALARM_URI = Uri.parse("android-app://com.myclockapp/set_alarm_page");

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...

        // Get the intent
        Intent intent = getIntent();
        if (AlarmClock.ACTION_SET_ALARM.equals(intent.getAction())) {
            if (intent.hasExtra(AlarmClock.EXTRA_HOUR)) {
                // Step 2: get the rest of the intent extras and set an alarm
                ...
            }

            // Step 3: report the action through the App Indexing API
            Thing alarm = new Thing.Builder()
                    .setName("Alarm for 4:00 PM")
                    .setDescription("Alarm set for 4:00 PM, with the 'Argon' ringtone"
                                    + " and vibrate turned on.")
                    .setUrl(APP_URI)
                    .build();

            Action setAlarmAction = new Action.Builder(Action.TYPE_ADD)
                    .setObject(alarm)
                    .setActionStatus(Action.STATUS_TYPE_COMPLETED)
                    .build();

            AppIndex.AppIndexApi.end(mClient, setAlarmAction);
        }
    }

    ...

}

上面是是一个完整的示例,演示如何处理传入意图,并使用App Indexing API来报告用户成功设置了一个警报。

  • 如需创建新闹铃,请使用 ACTION_SET_ALARM 操作并使用下文介绍的 extra 指定时间和消息等闹铃详细信息。
EXTRA_HOUR (可选):闹钟的小时被设置。
EXTRA_MINUTES (可选):闹钟的分钟被设置。
EXTRA_DAYS (可选):平日用于重复报警。
EXTRA_MESSAGE (可选):用于闹钟的的自定义消息。
EXTRA_RINGTONE (可选):铃声与此闹钟进行播放。
EXTRA_VIBRATE (可选):是否以激活该闹钟的设备振动器。
EXTRA_SKIP_UI (可选):是否要设置该闹钟显示的活性。
常值:“android.intent.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);
    }
}

这里要注意:为了调用 ACTION_SET_ALARM Intent,您的应用必须具有 SET_ALARM 权限:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_ALARM" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 如需创建倒计时器,请使用 ACTION_SET_TIMER 操作并使用下文介绍的 extra 指定持续时间等定时器详细信息,这个动作要求的定时器为特定开始length的时间。如果没有length指定,则实现应该开始一个活动,能够设定一个计时器(的EXTRA_SKIP_UI在这种情况下被忽略)。如果length指定了,并且EXTRA_SKIP_UI是true,它已被驳回后,实施中应删除此计时器。如果相同的,未使用的计时器都存在参数匹配,实现可重复使用它,而不是创建一个新的(在这种情况下,计时器不应该被解雇之后去除)。这个动作通常启动定时器。
EXTRA_LENGTH (可选):该定时器的长度被设置。
EXTRA_MESSAGE (可选):定时器自定义消息。
EXTRA_SKIP_UI (可选):是否为设置这个定时器显示的活性。
常值:“android.intent.action.SET_TIMER”
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);
    }
}

同样的,为了调用 ACTION_SET_TIMER Intent,您的应用必须具有 SET_ALARM 权限:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_TIMER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 如需显示闹铃列表,请使用 ACTION_SHOW_ALARMS 操作。
    尽管调用此 Intent 的应用并不多(使用它的主要是系统应用),但任何充当闹钟的应用都应实现此 Intent 过滤器,并通过显示现有闹铃列表作出响应。
<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SHOW_ALARMS" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 如需向用户的日历添加新事件,请使用 ACTION_INSERT 操作指定具有 Events.CONTENT_URI 的数据 URI。 然后您就可以使用下文介绍的 extra 指定事件的各类详细信息。数据URI:Events.CONTENT_URI
    操作:ACTION_INSERT
    传的值(Extra):
EXTRA_EVENT_ALL_DAY
一个布尔型值,指定此事件是否为全天事件。
EXTRA_EVENT_BEGIN_TIME
事件的开始时间(从新纪年开始计算的毫秒数)。
EXTRA_EVENT_END_TIME
事件的结束时间(从新纪年开始计算的毫秒数)。
TITLE
事件标题。
DESCRIPTION
事件说明。
EVENT_LOCATION
事件地点。
EXTRA_EMAIL
以逗号分隔的受邀者电子邮件地址列表。
可使用 CalendarContract.EventsColumns 类中定义的常量指定许多其他事件详细信息。

实例代码:

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>
  • 如需打开相机应用并接收拍摄的照片或视频,请使用 ACTION_IMAGE_CAPTURE 或 ACTION_VIDEO_CAPTURE 操作。此外,还可在 EXTRA_OUTPUT extra 中指定您希望相机将照片或视频保存到的 URI 位置。
    传的值(Extra):
EXTRA_OUTPUT
相机应用应将照片或视频文件保存到的 URI 位置(Uri 对象形式)。
当相机应用成功将焦点归还给您的 Activity(您的应用收到 onActivityResult() 回调)时,您可以按通过 EXTRA_OUTPUT 值指定的 URI 访问照片或视频。
//注:当您使用 ACTION_IMAGE_CAPTURE 拍摄照片时,相机可能还会在结果 Intent 中返回缩小尺寸的照片副本(缩略图),这个副本以 Bitmap 形式保存在名为 "data" 的 extra 字段中。
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
        ...
    }
}

过滤器如是写:

<activity ...>
    <intent-filter>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

只拍摄照片:

<manifest ... >
    <uses-feature android:name="android.hardware.camera"
                  android:required="true" />
    ...
</manifest>

-----------------------------------------------------------
static final int REQUEST_IMAGE_CAPTURE = 1;

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    }
}
  • 只拍摄视频:
<manifest ... >
    <uses-feature android:name="android.hardware.camera"
                  android:required="true" />
    ...
</manifest>
--------------------------------------------------------

static final int REQUEST_VIDEO_CAPTURE = 1;

private void dispatchTakeVideoIntent() {
    Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
    if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
    }
}
  • 如需以静态图像模式打开相机应用,请使用 INTENT_ACTION_STILL_IMAGE_CAMERA 操作。
public void capturePhoto() {
    Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(intent);
    }
}
<activity ...>
    <intent-filter>
        <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 如需以视频模式打开相机应用,请使用 INTENT_ACTION_VIDEO_CAMERA 操作。
public void capturePhoto() {
    Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(intent);
    }
}
<activity ...>
    <intent-filter>
        <action android:name="android.media.action.VIDEO_CAMERA" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 如需让用户选择联系人和为您的应用提供对所有联系人信息的访问权限,请使用 ACTION_PICK 操作,并将 MIME 类型指定为 Contacts.CONTENT_TYPE。
    传送至您的 onActivityResult() 回调的结果 Intent 包含指向所选联系人的 content: URI。响应会利用 Contacts Provider API 为您的应用授予该联系人的临时读取权限,即使您的应用不具备 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
        ...
    }
}

就介绍这么多,这就很容易找见隐式Intent的规律了吧,其他的比如,选择特定联系人之类的,可直接在网上搜到,至于能Intent什么,我这里直接全部列出来,需要Intent啥样的参数,你就搜什么就OK了,对了强调一下,有的需要权限,有的则也需要过滤器哟:
1、选择联系人
2、选择特定联系人数据
3、查看联系人
4、编辑现有联系人
5、插入联系人
6、撰写带有可选附件的电子邮件
7、检索特定类型的文件
8、打开特定类型的文件
9、叫车
10、显示地图上的位置
11、播放媒体文件
12、基于搜索查询播放音乐
13、创建笔记
14、发起通话
15、使用特定应用搜索,我建议尽量看看这段视频,有惊喜。
16、执行网页搜索
17、打开特定设置部分
18、撰写带附件的短信/彩信
19、加载网址


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值