打造能分享内容的App(一)——分享简单数据

https://developer.android.google.cn/training/sharing/send.html

 

给其他App发送简单的数据

当你构建一个Intent的时候,你肯定指定了你的Intent想要“触发”的动作。Android定义了一些动作,包括 ACTION_SEND ,你大概能猜到,表示这个Intent正在把数据从一个Activity发送给另一个Activity,甚至能跨进程限制。要发送数据给另一个Activity,你要做的就是指定数据和类型,系统会识别兼容的Activity来接收并显示给用户(如果有多重选项的话)或者立即打开Activity(如果只有一个选项的话)。同样,你可以在你的manifest文件里指明你的Activities能接收的数据类型来给通知别的应用。

应用之间使用Intent来发送和接收数据经常应用于社交内容分享。Intents可以让用户方便、快捷的使用他们最喜欢的应用来分享信息。

注意:在 ActionBar 上添加一个分享动作项目最好的方式是使用 ShareActionProvider ,在 API 14中就可以使用了。

发送文本内容

最直接、最常用的使用 ACTION_SEND 动作的就是从一个Activity发送文本内容给另一个Activity.比如,内置浏览器App可以把当前页面的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);

 

如果有已安装的应用的过滤器可以匹配 ACTION_SEND 和 MIME 类型的 text/plain,Android 系统就会允许它;如果有多个应用匹配,系统就会展示允许用户选择一个App的消歧义的对话框(一个“选择器”)。

但是,如果你调用 Intent.createChooser(), 传递给你的 Intent 对象,它就会返回一个永远显示选择器的版本的Intent.这样有以下优点:

  • 即使用户之前给这个Intent选择了一个默认动作,选择器依然会显示
  • 如果没有应用能匹配,Android会显示一条系统消息
  • 你可以给选择器对话框指定标题

这是升级版的代码:

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_EMAIL, EXTRA_CC, EXTRA_BCC, EXTRA_SUBJECT. 如果接受的应用没有设计使用它们的功能,就会直接无视它们。

注意:一些电子邮件应用,比如 Gmail, 想要的是一个 String[] 类型的额外信息,比如 EXTRA_EMAIL 和 EXTRA_CC, 使用 putExtra(String, String[]) 方法把这些添加到你的Intent.

发送二进制内容

二进制数据使用设置了合适的MIME类型的 ACTION_SEND 动作并把 URI 替换为一个叫做 EXRA_STREAM 额外数据里的数据来分享。

这种方式经常用来分享图片,不过也可以用于分享任何二进制的内容:

1 Intent shareIntent = new Intent();
2 shareIntent.setAction(Intent.ACTION_SEND);
3 shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
4 shareIntent.setType("image/jpeg");
5 startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));

 

以下请注意:

  • 你可以使用 "*/*" 这类的 MIME 类型,但这种只适用于匹配哪些能够处理通用数据流的Activity
  • 接收应用需要权限来访问 Uri 指向的数据。推荐的方式有这些:
    • 在你自己的 ContentProvider 里面存储数据,确保其他的App有正确的权限来访问你的内容提供器。使用 per-URI permissions 提供访问权限的首选机制是临时并仅授予接收应用权限。一种简单的方式来创建一个像这样的 ContentProvider 就是使用 FileProvider 的 helper 类。
    • 使用系统的 MediaStore. MediaStore 的主要用途就是 视频、音频和图像 MIME类型,但是从 Android 3.0起,它也可以存储非媒体类型。使用 scanFile() 可以把文件插入 MediaStore里,之后 一个 content:// 风格适合分享的 Uri 就被传递给提供了 onScanCompleted() 的回调。需要注意的是,一旦添加到了系统的 MediaStore 里,那内容就可以被设备上的任何 App 访问。

发送多条内容

要分享多条内容,使用一个带有指向了内容的 URIs 列表的 ACTION_SEDN_MULTIPLE 动作。 MIME 类型根据你分享的内容的混合进行变化。比如,如果你要分享3个 JPEG 图片,类型依然是 “image/jpeg” . 对于一个图片类型的混合,它应该使用 "image/*" 来匹配能够处理任何类型图片的 Activity. 如果你要分享多种文件类型,你应该只使用 “*/*”. 就像之前说的,取决于接收应用来解析并处理你的数据。举例如下:

1 ArrayList<Uri> imageUris = new ArrayList<Uri>();
2 imageUris.add(imageUri1); // Add your image URIs here
3 imageUris.add(imageUri2);
4 
5 Intent shareIntent = new Intent();
6 shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
7 shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
8 shareIntent.setType("image/*");
9 startActivity(Intent.createChooser(shareIntent, "Share images to.."));

 

和以前一样,确保提供的 URIs 指向的是接收应用能访问的数据。

 

https://developer.android.google.cn/training/sharing/receive.html

从其他App接收简单数据

就像你的App可以给其他应用发送数据一样,它也能简单的从其他应用接收数据。想想用户是如何跟你的应用交互的,你想从别的应用接收哪些数据。比如,一个社交网络应用可能会对接收文本内容感兴趣,比如从其他App那收到的一个有趣的网络地址。 Google+ 应用技能接收文本内容也可以接收单张或多张图片。有了这个应用,用户可以轻松的从 Android 图片 App 里选择照片来发一篇新的 Google+ 文章。

升级你的Manifest

Intent过滤器会通知系统哪些应用组件接收哪种类型的Intent. 和上一节课中如何使用 ACTION_SEND 来构建Intent一样,为了能接收这个动作的Intent,你需要建立Intent过滤器。在manifest文件里定义一个intent过滤器,使用 <intent-filter> 元素。比如,如果你的应用处理接收的文本内容,单张任意类型的图片,或者多张任意类型的图片,你的manifest文件大概是这样:

 1 <activity android:name=".ui.MyActivity" >
 2     <intent-filter>
 3         <action android:name="android.intent.action.SEND" />
 4         <category android:name="android.intent.category.DEFAULT" />
 5         <data android:mimeType="image/*" />
 6     </intent-filter>
 7     <intent-filter>
 8         <action android:name="android.intent.action.SEND" />
 9         <category android:name="android.intent.category.DEFAULT" />
10         <data android:mimeType="text/plain" />
11     </intent-filter>
12     <intent-filter>
13         <action android:name="android.intent.action.SEND_MULTIPLE" />
14         <category android:name="android.intent.category.DEFAULT" />
15         <data android:mimeType="image/*" />
16     </intent-filter>
17 </activity>

 

当另一个应用构建了一个intent来试着分享这些东西并把它传递给 startActivity(), 你的应用会在intent选择器里被列为选项。如果用户选择了你的应用,对应的Activity(上面的例子中是 .ui.MyActivity)将会被启动。之后如何合适的处理这些内容就取决于你的代码和UI了。

处理发来的内容

要处理被Intent发来的内容,先调用 getIntent() 来获取Intent对象。一旦你获取到了对象,你可以检查它的内容来决定下一步怎么做。要记住,如果这个Activity能被系统的其他部分启动,比如登录器,那么你就会需要考虑合适检查intent了。

 1 void onCreate (Bundle savedInstanceState) {
 2     ...
 3     // Get intent, action and MIME type
 4     Intent intent = getIntent();
 5     String action = intent.getAction();
 6     String type = intent.getType();
 7 
 8     if (Intent.ACTION_SEND.equals(action) && type != null) {
 9         if ("text/plain".equals(type)) {
10             handleSendText(intent); // Handle text being sent
11         } else if (type.startsWith("image/")) {
12             handleSendImage(intent); // Handle single image being sent
13         }
14     } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
15         if (type.startsWith("image/")) {
16             handleSendMultipleImages(intent); // Handle multiple images being sent
17         }
18     } else {
19         // Handle other intents, such as being started from the home screen
20     }
21     ...
22 }
23 
24 void handleSendText(Intent intent) {
25     String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
26     if (sharedText != null) {
27         // Update UI to reflect text being shared
28     }
29 }
30 
31 void handleSendImage(Intent intent) {
32     Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
33     if (imageUri != null) {
34         // Update UI to reflect image being shared
35     }
36 }
37 
38 void handleSendMultipleImages(Intent intent) {
39     ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
40     if (imageUris != null) {
41         // Update UI to reflect multiple images being shared
42     }
43 }

 

  • 警告:要格外小心的检查外来的数据,你永远不会知道其他的应用会给你发来什么。比如,设置了错误类型的MIME内容,或者超大的图片。同样,同时也要记得,在独立的线程里面处理二进制数据,而不是在主线程(“UI”)里处理。

升级UI可能想填充一个EditText一样简单,或者也会像给给一张图片应用一个有趣的滤镜一样复杂。这都取决于你的应用下一步做了什么。

https://developer.android.google.cn/training/sharing/shareaction.html

添加一个简单的分享动作

在Android 4.0(API Level 14)之后,使用 ActionProvider 在你的 ActionBar 上引用一个有效而对用户有好的分享动作已经越来越简单了。ActionProvider,一旦成为附属在动作条上的菜单项目,就可以同时处理那个项目的外表和行为。就像在 ShareActionProvider 中,你提供了一个分享 Intent 然后它就完成了剩下的事。

注意 ShareActionProvider 在 API Level 14或更高的版本中可以使用

升级菜单声明

要开始使用 ShareActionProvider ,需要在你的 menu resource 文件里相应的 <item>条目中定义 android:actionProviderClass 属性:

<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 中的外表和功能负责。但是,你会需要告诉提供器你想要分享的是什么。

设置分享Intent

为了让 ShareActionProvider 起作用,你必须给它提供一个分享Intent. 这个分享Intent应该和发送简单的数据给其他App那节课中形容的一样,带有 ACTION_SEND 动作和使用额外方法比如 EXTRA_TEXT 、 EXTRA_STREAM 等设置的额外数据。要分派一个分享Intent,先在你的Activity 或者 Fragment 中渲染的菜单资源中找到相应的 MenuItem. 接下爱,调用 MenuItem.getActionProvider() 来回收一个 ShareActionProvider 实例。使用 setShareIntent() 来升级和动作项目相关联的分享 Intent. 举例如下:

 1 private ShareActionProvider mShareActionProvider;
 2 ...
 3 
 4 @Override
 5 public boolean onCreateOptionsMenu(Menu menu) {
 6     // Inflate menu resource file.
 7     getMenuInflater().inflate(R.menu.share_menu, menu);
 8 
 9     // Locate MenuItem with ShareActionProvider
10     MenuItem item = menu.findItem(R.id.menu_item_share);
11 
12     // Fetch and store ShareActionProvider
13     mShareActionProvider = (ShareActionProvider) item.getActionProvider();
14 
15     // Return true to display menu
16     return true;
17 }
18 
19 // Call to update the share intent
20 private void setShareIntent(Intent shareIntent) {
21     if (mShareActionProvider != null) {
22         mShareActionProvider.setShareIntent(shareIntent);
23     }
24 }

你可能在创建你的菜单时只需要设置分享Intent一次,或者你可能想在 UI 变化的时候设置或者升级它。比如,当你在相册App里全屏查看照片,分享Intent就会在你翻动相片的时候改变。

 

posted @ 2017-08-11 12:06  Kevinzh64  阅读(448)  评论(0)    收藏  举报