内容分享是Android App很重要的一个功能。借助内容分享的功能,你可以发送数据给其他APP,可以接收其他APP发来的数据,还可以发送文件或者图片到其他的设备,实现文件的分享功能。下面就从3个方面总结一下Android的内容分享功能。
在Activity中发送数据给另一个Activity或者另一个APP都可以通过action 为 ACTION_SEND
的Intent来完成。Intent中可以设置要分享的数据以及分享的数据类型。系统会根据Intent查找有哪些APP可以处理该Intent,如果有多个应用能够处理该Intent,那么系统会弹出一个选择列表给用户选择,如果只有一个则会直接调起该应用来处理Intent。
最常见的情况是分享一些文本内容给其他APP。比如我们浏览器APP可以分享当前页面的URL链接给其他应用,通常是分享一篇文章或者一个网址。下面代码片段发送一段简单的文字给其他APP:
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);
如果系统中安装有能处理ACTION_SEND
和text/plain
类型的数据的APP,系统就会启动它来处理。如果有多个的就会弹出如下类似的对话框:
有时候我们希望在任何情况下都弹出选择框让用户选择,这时我们可以用到Intent.createChooser
,这种方式还可以指定对话框的标题
startActivity(Intent.createChooser(intent,"分享文字到"));
上面分享的数据是通过EXTRA_TEXT
字段指定的,其实我们还可指定其他字段诸如EXTRA_EMAIL
、EXTRA_CC
、EXTRA_BCC
、EXTRA_SUBJECT
,这些通常用于发送邮件内容,不过在如果目标APP不需要这些内容可以直接忽略。
二进制内容通常是一些图片文件,通过EXTRA_STREAM
可以指定要分享的二进制内容。
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, mImageUri);
intent.setType("image/jpeg");
startActivity(Intent.createChooser(intent,"分享到"));
需要注意的是,处理该分享Intent的APP必须要有访问图片的权限,否则将不能正确处理请求。有2中方法可以达到目的:
将需要分享的二进制内容存储在自定义的ContentProvider
中,确保其他应用能够访问到该provider。通常的做法是针对当前的URI提供访问权限,这种授权是临时的并且只针对接收该Intent的应用。系统提供的FileProvider
类,让我们可以很容易做到这一点。关于FileProvider
的用法,我们会在下一篇文章中讲到。
第二种方法是使用系统的MediaStore
类。在Android 3.0之前,MediaStore
主要用来存储图片、音视频等内容,从3.0开始也可以用来存储其他类型的二进制内容。MediaStore
通过扫描文件(scanFile()
方法)将文件信息插入到MediaStore
,扫描完后onScanComplete
方法会被回调,该回调方法会传入一个形如content://
格式的uri用于分享。扫描通常是在外存目录(Music、Image等目录)中有新的文件时自动进行的。
有时候我们想同时分享多张图片,这时候需要用到ACTION_SEND_MULTIPLE
。通过指定一系列图片的URI来同时分享多张图片。同样我们要确保其他应用有访问这些uri的权限。
ArrayList<Uri> imageUris = new ArrayList<Uri>();
imageUris.add(imageUri1); // 在这里添加要分享的图片的uri
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, "分享图片到"));
上面讲述了如何分享数据给其他的APP,接下来讲一下如何接收处理来自其他APP的分享数据。
首先要定义处理Intent
的Activity
,并在AndroidManifest.xml
中注册能够接受的IntentFilter
.例如,下面的代码片段定义了一个能够处理来自其他APP分享的文本和图片内容的Activity:
<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>
当有APP通过构造这样的Intent来分享数据时,我的APP就会出现在弹出的选择框中供用户选择。如果用户选择了我们的APP,那么上面注册的MyActivity
就会被启动运行。接下来要做的就是在MyActivity
里完成处理这些分享的逻辑代码。
private void handleIntent() {
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if(TextUtils.equals(Intent.ACTION_SEND,action) && type != null) {
if (TextUtils.equals(type, "text/plain")) {
//处理文本内容
handleTextIntent(intent);
} else {
//处理图片内容
handleImageIntent(intent);
}
}
}
private void handleImageIntent(Intent pIntent) {
Uri uri = pIntent.getParcelableExtra(Intent.EXTRA_STREAM);
if(uri == null) return;
mImageIv.setImageURI(uri);
}
private void handleTextIntent(Intent pIntent) {
String content = pIntent.getStringExtra(Intent.EXTRA_TEXT);
mContentTv.setText(content == null ? "no content" : content);
}
处理数据时一定要检查数据的合理性,因为我们不知道接收的是何种数据,所以一定要考虑的各种情况,增强APP的健壮性。
讲完了简单数据的分享和处理,还跟大家讲一讲在Android 4.0中新增的一种分享操作ShareActionProvider
。分享操作的按钮一般放在Toolbar中,通过使用ShareActionProvider
可以简单高效并且很友好的实现分享操作。
像为Toolbar添加普通的菜单项一样,我们需要声明一个用于分享的菜单项。不同的是,我们要在菜单项中指定android:actionProviderClass
属性。代码如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/menu_share" app:showAsAction="always" android:title="分享" android:actionProviderClass="android.widget.ShareActionProvider"/>
</menu>
上述代码中,我们指定android:actionProviderClass
的值为系统类ShareActionProvider
,这个类为我们做了分享操作的大部分工作,我们只需要在适当的时候设置要分享的内容的Intent给它就行了。
为了让ShareActionProvider
正常工作,我们必需要给它设置要分享的内容的Intent。Intent的构造方法和普通的Intent一样,指定action 为 ACTION_SEND
或ACTION_SEND_MULTIPLE
,同时设定分享内容和所属的类型,然后调用ShareActionProvider#setShareIntent
方法。这样当我们触发分享菜单项时,就会执行相应的分享操作。代码如下:
//初始化菜单,获取ShareActionProvider对象
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_itmes, menu);
MenuItem shareItem = menu.findItem(R.id.menu_share);
mActionProvider = (ShareActionProvider)shareItem.getActionProvider();
return true;
}
......
//监听文本内容变化,更新要分享的Intent
@Override
public void afterTextChanged(Editable s) {
String text = s.toString();
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, text);
intent.setType("text/plain");
setShareIntent(intent);
}
......
//设置Intent到ShareActionProvider
private void setShareIntent(Intent pIntent) {
if(mActionProvider != null){
mActionProvider.setShareIntent(pIntent);
}
}
ACTION_SEND
和ACTION_SENDTO
对比ACTION_SEND
的发送动作的目标是没有指定的,只要匹配了action和dataType的activity都可以处理。
ACTION_SENDTO
是发送给特定的目标,目标通常通过data uri来指定,即除了匹配action和dataType,还必须匹配data uri,如果Intent中没有指定 data URI 则系统匹配不到任何ACTIVITY。
分享简单的文本内容是Android APP中常用的功能,但是文本内容太少,很多时候需要分享图片,大文件的操作,这就涉及到文件分享,下一章将详细介绍分享文件的一些重点知识,敬请期待。