和其他平台的应用不一样,安卓的应用不一定需要从主函数启动,一个应用可以启动其他应用。这是因为每个应用都能响应不同的动作,比如相机能相应照相这个动作,很多社交软件都能相应分享动作,视频播放器能响应播放视屏的动作。发送一个动作,系统会查询能够响应相应动作的应用,然后显示出可以响应这个动作的应用。这就应用启动其他应用的原理。常见的场景有,你的应用要拍一张照片,你当然可以自己写一个相机程序,但是你可以调用系统自带的相机,发送一个拍照的动作,然后请求返回照片,就能从相机得到一张照片了,当你的用户需要分享东西时,只需要发送一个Send的动作就可以将内容分享到其他应用中。
在一个应用程序内,Activity通过Intent 启动其他Activity ,启动其他应用也是使用Intent,其本质还是启动Activity,不过不是本应用内的Activity,而是其他其他应用的Activity。当启动本应用内的Activity,应用是你自己写的,你知道应用内所有Activity以及他们的功能,所以你可以指定启动哪个Activity,这样的Intent叫显示 Intent(explicit intent),在Intent 中指定要启动的组件(包括Activity,Service,Broad Cast)。但是如果要其他应用的Activity,你并不知道其他应用内有什么Activity,有什么功能,所以不能直接启动。这就需要使用隐式intent(implicit intent),在Intent中指定要执行的动作,系统会从安装的程序中查询能够响应这个动作的组件,如果有应用能响应这个动作,就会显示这些应用,如果没有,会出现错误(要避免这种情况)。
使用隐式Intent
使用隐式Intent,只需要在Intent中声明你想要执行的动作,你想让其他应用做的事情。比如说分享,查看,编辑或者从其他应用获取数据。在传递动作的时候,你也可以传递一些数据,例如你有个地址,想通过地图来查看这个地址。
比如你的用户需要将东西分享到其他应用中,下面是一个简单的用法
Intent intent = new Intent(Intent.ACTION_SEND);
startActivity(intent);
这里只指定了一个发送的动作,但是没有指定发送的内容,要发送内容的类型,这个动作可能执行,有可能出错,这取决于用户设备守丧安装的应用。为了确保至少有一个应用能响应这个动作,可以使用如下代码
/**
* 确定设备上是否有能够响应给定Intent的应用,如果有返回true,否则返回false
* @param intent 要检查的intent
* @return true如果有应用可以响应这个Intent,否则返回false
*/
public boolean matchIntent(Intent intent){
PackageManager manager = getPackageManager();
List activities = manager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
return activities.size() > 0;
}
继续上面的分享动作,当用户要分享或查看什么东西时,肯定已经有内容,可能时Uri数据或者其他数据。
假设你的应用内有个网址,需要系统的浏览器打开
Uri webPage = Uri.parse("http://www.baidu.com");
Intent intent = new Intent(Intent.ACTION_VIEW,webPage);
if (matchIntent(intent))
startActivity(intent);
Intent中还可以存放额外的数据,能够存储不同的数据类型,通过Intent将这些数据传递到能启动它的组件,然后这个组件会接受处理这些额外的数据。通过putExtra()来存放额外的数据。
假设用户要分享一段文本,可以使用如下代码
String share = "hello!";
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT,share);
if (matchIntent(intent))
startActivity(intent);
当使用putExtra时,第一个参数要用Intent类里的Standard extra data keys.如果你自己定义键,别的应用并不知道你的键,就无法从Intent中取出你要分享的数据。你的应用如果要响应其他应用的动作,也要使用Intent类中提供的键来获取Intetn传递过来的额外的数据。如果大家都遵守这个标准,就能保证传递正确的数据,取出正确的数据。
从其他Activity返回结果
有时候启动其他Activity只是借用它的功能来获取信息,比如使用照相机拍照,并获取拍照的结果。从系统图库中选取图片,从通讯录中选取某个联系人的信息。
要从启动的Activity中返回结果,要用startActivityForResult()来启动Activity,该方法接受两个参数,第一个是你想要执行的动作,第二个是一个整数(requestCode),接受返回的结果时,将返回的requestCode和你启动这个Activity时的requestCode进行比较,如果相等,说明确实是你启动了这个Activity,它也返回了数据。
然后在重写onActivityResult(int requestCode,int resultCode,Intent data),处理返回过来的数据。这个方法接受三个参数,前两个都是整数,第三个是Intent,它携带返回的数据。前两个参数用来验证是否返回了数据。requestCode和启动Activity传递的参数进行比较,如果相等,说明确实是你启动了这个Activity,它也返回了数据。resultCode代表是否成功返回数据,如果resultCode 和Activity.REULT_OK相等,说明成功返回了数据。
下面代码展示启动系统自带的相机程序拍照,返回照片,并将照片显示在屏幕上。
private void takePhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (matchIntent(intent)
startActivityForResult(intent,REQUEST_IAMGE_CAPTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IAMGE_CAPTURE && resultCode == RESULT_OK){
Bundle extra = data.getExtras();
Bitmap imageBitmap = (Bitmap) extra.get("data");
mImage.setImageBitmap(imageBitmap);
}
}
允许他应用启动你的应用
你可以用户手机安装的其他应用程序。你也可以让其他应用启动你的应用。如果你的应用是一款社交类应用,用户可以将其他应用中的信息分享到你的应用中,当然你需要处理这些传递过来的信息,让它们以正确的方式呈现在你的应用中。
添加Intent Filter
如果允许其他应用启动你的应用,首先要添加Intent Filter。决定让哪个组件处理动作,然后在这个组件下添加Intent Filter.Intent 下包含的内容有
- Action 你的应用能响应的动作。例如
ACTION_SEND
或ACTION_VIEW
,但是intent filter中不能只写ACTION_SEND
,需要写完整名字,android.intent.action.SEND
- Data,你的应用能够处理的数据类型。可以指定MIME或者URI前缀,比如
text/plain
- category 组件的类别,如下代码,将activity作为应用启动后显示的第一屏。
<category android:name="android.intent.category.LAUNCHER" />
你要接受的intent 只有一个动作和一种数据类型,但是你可以在intent filter中定义多个action和Data标签。
当一个应用使用隐式Intent时,系统检索系统上所有应用的manifest file,检索逐一检索它们的Intent Filter,比较action ,data ,catogery,如果这三个项都匹配,则该应用能想用这个Intent,否则不能响应这个Intent.
在Acitivity中处理接收到的Intent
通过getIntent获取接收到的Intent,然后获取相关数据。
假设应用能响应ACTION_SEND
,数据类型为text/plain
的Intent。
Intent Filter如下
<activity android:name=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="text/plain"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
处理Intent的Activity如下
Main2Activity.java
package com.example.test.testshare;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class Main2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Intent intent = getIntent();
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
TextView show = new TextView(this);
show.setText(text);
setContentView(show);
}
}