让你的Android应用与外部元素互动起来

传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229
html

        一个Android应用程序一般有几个activities。每一个act显示一个用户接口容许用户执行一个指定的任务。用户从一个act到另外一个act,你的App必须使用一个Intent对象来定义你App想作些什么事。当你经过一个Intent调用startActivity()方法时,系统会使用Intent来鉴定和启动合适的App组件。一个Intent能够明确的启动一个特定的组件(如一个特定的act实例)或隐式启动任何能够处理预约动做的组件,本章咱们将讲述怎么使用Intent来执行与其余Apps的一些交互,例如启动另外一个App,从那个App接收结果。并使你的应用程序可以响应来自其余App的intents。java

1发送用户到另外一个App

        Android最重要的一个特性之一就是发送用户到另外一个App并基于“动做”来执行它的能力。例如,若是你的app有商业地址想要显示在地图上,你不得不在你的App中新建一个activity来显示地图。其实更好的办法是使用Intent发送一个查看地图的外部请求。Android系统会启动那个能查看地址的App。一般,咱们使用一个明确的Intent,它定义的明确的类名。然而,当你想有一个单独的应用程序执行时,如“查看地图”,你必须使用一个隐式的Intent。本节讲述如何为一个特定的动做建立隐含的意图,以及怎样用它来启动执行另外一个应用程序中的Activity。

1.1构建一个隐式的Intent

        隐式intents不用申明启动组件的类名,但须要申明执行的动做。动做指定你想要作的事情,如view(查看),edit(编辑),send(发送)或得到某事物。Intents常常包托一些与动做相关联的税局,如你想要查看的地址,或者你想要发送的email信息。这取决于你想要建立的Intent所发送的数据,数据多是一个Uri或intent根本不须要数据也能发送。
使用Uri数据拨打电话:
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
        当你的app经过startActivity()调用intent时,电话app根据给定的电话号码发起呼叫。
查看一个地图:
// 基于地址的地图点
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// 或基于经纬度的地图点
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z参数表示缩放级别
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
查看一个web页面:
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
        其余种类的隐式intents须要”extra”数据来提供不一样的数据类型,如一个字符串。你能使用putExtra()方法来添加一个或更多extra 数据。默认的,系统经过基于Uri的intent来肯定适当的MIME(Multipurpose Internet Mail Extensions)类型。若是你在intent中不包含一个Uri,你应该使用setType()来指定intent相关联的数据类型。设置MIME类型来进一步指定activities将要接收的intent类型。
发送带有附件的电子邮件:
Intent emailIntent = new Intent(Intent.ACTION_SEND);
//没有Uri的intent,因此须要声明”text/plain”的MIME类型
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // 收件人
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
建立一个日历事件:
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
注意: 对于日历事件的intent只在API Level或更高版本下才支持。

1.2验证一个App接收的Intent

        咱们老是应该在调用一个intent以前先包含一个验证。这是一个好的习惯,由于若是你在app中调用intent后,若是没有可用的设备,那么你的app会崩溃.为了验证那个activity可用,咱们能够调用queryIntentActivities()来得到一个list,若是返回的List不为空,那么你能安全的使用intent。
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
        如isIntentSafe为true,那么表示至少有一个app能响应咱们的intent。若是false,表示没有一个app能处理这个intent。

1.3使用Intent启动一个Activity

        你能够建立intent并设置extra的信息,而后调用startActivity()。若是系统识别有多个activity能处理这个intent,那么它会显示一个对话框让你自主选择。若是只有一个activity的话,系统会当即启动这个activity。
        让咱们看看以下的代码,看它是怎么启动activity的:
// 构建intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// 验证上面的mapIntent
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
// 若是它是安全的就启动这个activity
if (isIntentSafe) {
    startActivity(mapIntent);
}

1.4显示APP选择器

        注意当你经过intent使用startActivity()启动activity时,若是有多个app响应,若是多个应用能够处理咱们的操做,而且用户可能想要每次启动不一样的app,好比一个”分享”的动做,分享的渠道可能有多个app组成,这样用户每次可能使用不一样的app。那么咱们可使用createChooser()来建立显示选择器。
Intent intent = new Intent(Intent.ACTION_SEND);
...
// 用于标题的文本资源例如"Share this photo with"
String title = getResources().getText(R.string.chooser_title);
// 建立并启动chooser
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);

2从Activity得到结果

        启动另外一个activity并不必定是单向的。咱们还能够启动另外一个activity,并接收返回结果.。若是须要接收返回结果,咱们可使用startActivityForResult()。L例如。你的应用启动一个摄像机app并接收拍摄照片的结果。固然,得到响应的activity必须被设计为返回一个结果,当它这么作时,它发送一个intent对象的结果。你的activity在onActivityResult()回调方法中会接收到这个intent。虽然咱们可使用明确的和隐式的intent,但这里实际建议你应该使用一个明确的intent,以确保收到了预期的结果。

2.1启动Activity

        使用startActivityForResult()方法,须要传递一个额外的int参数。Int参数的意思为”request code”,就是标识一个请求。当收到intent结果时,回调提供了相同的请求的代码,使应用程序能够正确识别结果,并决定如何处理它。
如何启动一个activity并容许用户选择一个联系人:
static final int PICK_CONTACT_REQUEST = 1;  // request code
...
private void pickContact() {
    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
    pickContactIntent.setType(Phone.CONTENT_TYPE); 
    startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}

2.2接收一个结果

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // 检查响应的请求
    if (requestCode == PICK_CONTACT_REQUEST) {
        // 确保请求是成功的
        if (resultCode == RESULT_OK) {
            // Do something...
        }
    }
}
        为了成功地处理结果,你必须明白,intent结果的格式将是什么。例如,People app(早些版本叫Contacts app)始终用content URI返回结果并识别被选择的联系人,Camera app在返回一个Bitmap。
将上面的代码扩展一下,让咱们看下怎样读取联系人数据:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //检查响应的请求
    if (requestCode == PICK_CONTACT_REQUEST) {
        //确保请求是成功的
        if (resultCode == RESULT_OK) {
            // 得到指向选定联系人的URI
            Uri contactUri = data.getData();
            //咱们只须要号码(NUMBER)列 
            String[] projection = {Phone.NUMBER};
 
            // 在联系人中执行查询,得到NUMBER column
            // 咱们不须要挑选或排序
            // 提示:  query()方法应该在单独的线程执行,避免阻塞UI线程
            // 考虑使用CursorLoader 执行查询
            Cursor cursor = getContentResolver()
                    .query(contactUri, projection, null, null, null);
            cursor.moveToFirst();
 
            // 从NUMBER column中检索电话号码
            int column = cursor.getColumnIndex(Phone.NUMBER);
            String number = cursor.getString(column);
 
            // 使用电话号码作些事情
        }
    }
}
注意:Android 2.3 (API level 9)之前,在Contacts Provider执行一个查询须要申明READ_CONTACTS权限,虽然在2.3开始有一个临时的权限可让你去读取Contacts Provider,但依旧不能查询。因此无论什么版本咱们都申明READ_CONTACTS权限便可。

3容许其余Apps启动你的Activity

        在android平台上,若是你要集成facebook的社交功能,那么你可使用facebokk提供的一个apk,里面集成了facebook的众多功能,如分享信息照片等。在实际开发过程当中,可能咱们须要开发这样的一个相似的apk,别担忧,android提供这样的功能而且很容易实现。

3.1添加一个Intent Filter

        咱们须要正确的定义intents,让activity能更好的处理。每个intent filter应该添加具体的action类型和数据类型。系统可能会发送一个给定的intent到一个activity,若是activity有一个intent filter并符合下列条件的intent对象:
Action
        一个用来执行动做的字符串名字。例如ACTION_SEND或ACTION_VIEW。在intent filter中的<action>节点指定它。必须是全称,不能使用API常量。
Data
        相关的intent中数据的描述。在intent filter中的<data>节点指定它。在这个节点中使用一个或多个属性,你能指定MIME类型,一个URI前缀,一个URI组合,或者是以上内容的组合。若是你不须要申明指定的Uri数据,那你仅指定 android:mimeType属性便可,例如text/plain或image/jpeg。
Category
        提供一种额外的方法来表示activity处理的intent,一般与用户手势和开始位置相关。系统支持几种不一样的类别,但大部分都不多使用,通常在intent filter中的<category>节点使用CATEGORY_DEFAULT。
下面的<intent-filter>中定义的内容表示在处理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"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>
        每个传入的intent只有一个动做和一种数据类型,但声明多个<data>,<action>,<category>也是OK的,若是动做和数据类型相互排斥的话,你就应该分开它们。加入你的activity处理文本和图像,而且使用ACTION_SEND和ACTION_SENDTO intents。这样就是错误的,在这种状况下你应该使用两个<intent-filter>来分开它们。由于SENDTO必须使用Uri数据,而且须要sms和smsto的scheme。
<activity android:name="ShareActivity">
    <!—为发送文本过滤; 接收SENDTO action 使用 sms URI schemes -->
    <intent-filter>
        <action android:name="android.intent.action.SENDTO"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="sms" />
        <data android:scheme="smsto" />
    </intent-filter>
    <!—为发送文本或图像过滤; 接收SEND action和文本或者图像数据 -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>
        为了接收隐式的intents,咱们必须在<intent-filter>中定义CATEGORY_DEFAULT中,若是没声明,那么你的activity不能解决处理隐式的intents。

3.2 在Activity中处理intent

        为了决定在你activity中想要处理的动做,你能在启动activity时读取intent。在启动activity时,调用getIntent()方法来检索启动activity的intent。你能在任意时刻这么作,但最好在onCreate()或onStart()中这样作。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //得到启动activity的intent
    Intent intent = getIntent();
    Uri data = intent.getData();
 
    // 解决intent类型想作什么
    if (intent.getType().indexOf("image/") != -1) {
        //处理图像数据
    } else if (intent.getType().equals("text/plain")) {
        // 处理文本
    }
}

3.3 返回一个结果

        若是你想要返回一个结果到你调用的activity,最简单的就是调用setResult()方法来指定结果代码和intent结果。当你的操做完成时,用户若是想要返回到最开始的activity,调用finish()来关闭和destroy你的activity便可。
// 建立intent来传递某种结果数据
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();
        咱们能够只指定result code。一般是RESULT_OK或RESULT_CANCELED。你能够添加额外的intent或者不添加。默认的result code是RESULT_CANCELED。因此若是用户在你设置result以前执行Back键,那么最初的activity收到的就是RESULT_CANCELED,这并非咱们预计的结果,这个细节请注意。
相关文章
相关标签/搜索