数据共享
能够相互交流和整合是Android应用非常重要的一个功能,所以才会有当已经有一个应用存在这个功能时,在你的应用中这个功能就不算是一个核心功能的说法。
本课将向你讲述通过Intent和ActionProvider在应用中接收和发送内容的一些方法。
发送内容到其它程序
当你实例化一个Intent对象时,你必须要为其指定你想要做什么事的意图。Android定义了一系列的动作属性,其中就包括ACTION_SEND,看它的名字你可能就已经猜到它的意思了,就是在同一进程或者不同进程中,从一个窗口往另一个窗口发送数据。为了能够在窗口之间传递数据,你需要指定数据和数据类型,这样系统才能够识别哪些窗口可以接收这些信息,然后将这些应用以一个对话框的形式显示出来(如果有多于一个应用可以执行这些操作的话)或者直接启动符合要求的窗口(如果只有一个应用满足条件)。同样的,你可以在你的清单文件Manifest.xml中为你的窗口设置数据类型,其它应用就可以在设置好对应类型的情况下跳转到你的窗口了。
在不同应用之间发送和接收数据在社交分享应用中使用得尤为地多,用户可以通过intent可以快捷方便的分享信息到他们喜欢的应用上去。
注意:分享功能实现的最好方式是使用ShareActionProvider在ActionBar上添加一个分享操作项,但前提是你的API版本是14及以上版本。
发送文本内容
使用ACTION_SEND最直接和最多的是在窗口间传送文本内容,比如系统内置的浏览器应用可以将当前显示的网页对应的URL地址以文本的方式分享给其它任何应用。可见以文本的形式通过邮件或者社交网络分享文章和网址是非常有用的,下面是窗口间传递文本内容的一个具体实现:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
startActivity(sendIntent);
如果当前设备中同时存在一个filter为”ACTION_SEND”,MIME类型为”text/plain”的窗口,android系统将会启动它,如果多于一个应用满足匹配条件,系统将显示一个列出所有能够启动应用的对话框供用户选择。当然了,如果你在实例化Intent的时候使用了语句”Intent.createChooser()”,android系统会直接显示你所选择的应用,这样做的好处在于:
1、 即使是用户之前从对话框中选择了一个默认的应用,经过上面的设置后,再次启动应用时会直接跳转到在代码中设置的应用;
2、 如果当前设备中没有符合条件的应用,android会显示一条系统提示信息;
3、 你可以为选择对话框设置标题。
下面是更新后的代码:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));
具体效果如上图所示。
或者,你可以为intent设置一些标准的extra:EXTRA_EMAIL,EXTRA_CC,EXTRA_BCC,EXTRA_SUBJECT。然而,如果接受这些消息的应用没有打算用这些extra,即使你这样设置了但什么事情也不会发生。别担心,即使应用没有处理这些信息,但程序还是会正常运行的。从技术的角度来讲,你最好是使用接收消息的应用自定义的extra。
注意:一些邮件应用,比如Gmail,你可以通过intent的putExtra(String,String[])方法来传递一些额外的EXTRA_EMAIL和EXTRA_CC信息给它们。
发送二进制内容
应用间传递二进制信息时,要ACTION_SEND结合设置MIME类型来使用,并且通过EXTRA_STREAM以URI的方式来传递这些数据,这种方式通常用于分享图片,但也可以分享其它任何是二进制的数据。
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));
在使用的过程中你需要注意以下几点:
1、 你可以将MIME的类型设置为”*/*”,但这样只会匹配哪些能够处理一般数据流的窗口;
2、 接收信息的应用需要有访问数据uri的权限,推荐的做法是:
(1) 用你自己的ContentProvider保存数据,并确保其它应用有访问你provider的权限,访问它的首选机制是使用per-URI权限,这些权限只授予给哪些能够接收到信息的应用。
(2) 使用系统的MediaStore,MediaStore旨在匹配MIME类型为音频、视频和图像。从Android 3.0起,mediaStore可以支持非多媒体类型了(详情查看MediaStore.Files)。通过调用scanFile()方法后,如果需要扫描的文件类型被系统所支持文件将被加入到MediaStore中,并且文件一旦加入到系统的MediaStore中,所有在设备上的应用都可以访问它。
发送多个内容数据段
通过ACTION_SEND_MULTIPLE操作结合执行内容的一个URI列表,便可以通过Intent分享多个内容数据段。MIME的类型取决于你所分享的内容。比如,如果你要分享3张图片,MIME的类型仍然是”image/jpeg”,如果是多个图片格式的话,它就应该被设置为”image/*”来匹配可以处理任何格式的图片资源。如果你分享的数据有多种类型,你就只能将MIME的类型设置为”*/*”。正如前面所描述的那样,这些都是由接收intent的应用解析和处理你的数据而定的,请看下面的例子:
ArrayList<Uri> imageUris = new ArrayList<Uri>();
imageUris.add(imageUri1); // Add your image URIs here
imageUris.add(imageUri2);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
shareIntent.setType("image/*");
startActivity(Intent.createChooser(shareIntent, "Share images to.."));
请确保接收intent的应用可以访问传递的uri所指向的数据。
接收从其它应用传递过来的数据
既然你的应用可以发送数据给其它应用,那同样也可以接收从其它应用传递过来的数据。想象一下用户是怎样和你的程序进行互动的,哪种数据类型是你希望从其它应用中接收的。比如,一个社交网络应用会倾向于接收纯文本内容,比如从其它应用传递过来的一个网页链接。比如Google+安卓客户端能够接收纯文本或者单个和多个图像。通过它,用户可以轻松地将画廊应用中的图片发送到Google+。
更新你的清单文件
通过清单文件中的Intent过滤器就可以让系统知道,你的应用希望接收那种类型的数据。就像之前的课程所讲,你可以在清单文件中定义一个intent过滤器来接收ACTION_SEND所发送的action。比如,如果你的应用可以操作接收的文本内容、可以是不同格式的一张图片,或者是多张不同格式的图片,你的清单文件看起来是这个样子的。
<activity android:name=".ui.MyActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
在清单文件中设置后这些信息后,当其它应用通过startActivity()传递符合过滤条件的数据类型的时候,你的应用将被系统作为可接受这些数据的应用而加入intent选择列表,如果用户选择了通过你的应用来启动,你应用的主窗口将被启动,然后就是该你操作这些数据了。
处理接收到的内容
为了能够处理通过Intent传递过来的内容,你需要通过getIntent()方法来获取Intent实例,一旦你获取到了Intent实例,你就可以做你想做的事情了。记住,如果这个窗口可以被系统的某个应用启动,比如桌面,你需要考虑intent为空的情况。比如:
void onCreate (Bundle savedInstanceState) {
...
// Get intent, action and MIME type
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
} else if (type.startsWith("image/")) {
handleSendImage(intent); // Handle single image being sent
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
if (type.startsWith("image/")) {
handleSendMultipleImages(intent); // Handle multiple images being sent
}
} else {
// Handle other intents, such as being started from the home screen
}
...
}
void handleSendText(Intent intent) {
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null) {
// Update UI to reflect text being shared
}
}
void handleSendImage(Intent intent) {
Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (imageUri != null) {
// Update UI to reflect image being shared
}
}
void handleSendMultipleImages(Intent intent) {
ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (imageUris != null) {
// Update UI to reflect multiple images being shared
}
}
注意:切记检查你接收到的信息,因为你不可能控制其它程序给你发送的内容,比如,其它应用传递过来的MIME类型可能是错的,或者传了一张非常大的图片。还有,如果你需要处理接收的二进制数据,记得开一个线程,不要直接在UI线程里面整。
更新的UI可能是一个简简单单的EditText,也可能是一个图像过滤窗口。
添加一个简单的分享操作
从Android 4.0开始,通过ActionProvider在操作栏上实现一个有良好用户体验的分享操作是非常简单的一个事情,一个ActionProvider,一旦与操作栏的某一个菜单项绑定,就可以接管这个菜单项的所有行为了,如果你使用的是ShareActionProvider,你只需要提供一个分享intent,其它的事情你就不用管了。
注意:只有在Android 4.0及以上的版本才支持ShareActionProvider。
更新菜单的定义
在使用ShareActionProviders时,你需要在菜单的资源文件中item标签下定义android:ctionProviderClass属性。
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_item_share"
android:showAsAction="ifRoom"
android:title="Share"
android:actionProviderClass="android.widget.ShareActionProvider" />
...
</menu>
这样,ShareActionProvider就可以接管该菜单项的所有行为了,但要记住,你需要告诉这个provider你希望分享什么。
设置分享Intent
为了让ShareActionProvider生效,你必须为其提供分享意图,分享意图可以是ACTION_SEND和EXTRA_TEXT、EXTRA_STREAM,具体实例如下:
private ShareActionProvider mShareActionProvider;
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate menu resource file.
getMenuInflater().inflate(R.menu.share_menu, menu);
// Locate MenuItem with ShareActionProvider
MenuItem item = menu.findItem(R.id.menu_item_share);
// Fetch and store ShareActionProvider
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
// Return true to display menu
return true;
}
// Call to update the share intent
private void setShareIntent(Intent shareIntent) {
if (mShareActionProvider != null) {
mShareActionProvider.setShareIntent(shareIntent);
}
}
一旦你创建你的菜单时你就需要设置分享意图,有可能在程序运行的过程中这个设置内容会更改,比如当你在画廊应用中全屏浏览图片的时候,分享的intent会在你图片切换时改变。
原文链接:Sharing Content