内容分享之分享简单数据

Android应用的一个重要的功能就是应用间可以相互交流和互相调用,自己的app只要做好自己核心的功能,其他非核心的功能如果存在可以直接调用的app就调用它们的,没必要重复造轮子.

本文将会告诉你一些通用的方法通过IntentActionProvider来进行应用间简单数据的发送和接收.(PS: 想了解更多关于Intent的介绍可以看之前的使用Intent来进行App间的基本交互).

1. 发送简单的数据给其他app

Intent中必须要带有action,在Android系统中定义了很多种action,其中有一种action可以用来在不同的activity之间甚至不同的进程之间进行数据传输,这个action就是ACTION_SEND.

1.1 发送文本内容

ACTION_SEND最直接和最常见的用法就是从一个activity发送文本内容给另外一个activity.例如内置的浏览器可以将当前页面的URL以文本的形式分享给任何的应用(可以匹配Intent的),这种方法对通过邮件或社交网络来分享文章或网页来说非常有用.如下实例:

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);

上面的代码有两点需要注意的:

  • 启动隐式的intent的时候,记得要先验证是否有activity来接收,具体可以参考之前的使用Intent来进行App间的基本交互).
  • 视情况选择是否使用chooser(候选框),时候候选框的好处是可以不用验证是否有activity来处理,没有会自动提醒;还有一个好处是可以自定义标题.

改进版的代码如下:

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
// with chooser
startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)));

注意:

  • 上面intent的 putExtra() 中的第一个参数用的是Intent.EXTRA_TEXT,这些Intent中定义的一些标准的extra,其他的也有EXTRA_EMAIL,EXTRA_CC等等,具体Intent的各种标准的属性可以看Intent;
  • intent的putExtra()中的第二个参数有的时候可能是string[],比如 EXTRA_EMAIL, EXTRA_CC等.

1.2 发送二进制的内容

二进制的数据可以用ACTION_SEND的action,合适的MIME类型以及EXTRA_STREAM和URI作为putExtra的两个参数来配合完成,这可以用来分享任何类型的二进制内容,下面看下常用的图片的分享:

Intent shareIntent = new Intent();
// 1. action
shareIntent.setAction(Intent.ACTION_SEND);
// 2. Intent.EXTRA_STREAM和uri类型的uriToImage
shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
// 3. 合适的MIME类型
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));

上面有几点需要注意:

  • You can use a MIME type of "*/*", but this will only match activities that are able to handle generic data streams.(对于这句话我不理解。。。。真在求证中..)
  • 接收该Intent的应用需要权限来访问Intent中的Uri的数据,推荐的方法两种:
    1. 将数据存在ContentProvider,并保证其他的app有正确的访问权限.
      对于访问权限的保证,首选的机制是给接收的应用提供per-URI permissions,这样就可以有效减少permission的滥用.
      对于ContentProvider的创建,可以使用FileProvider,这样会比较简单.
    2. 使用系统的MediaStore. MediaStore主要针对视频,音频和图片类型,但是从Android 3.0(API 11)开始,它也可以储存non-media类型(详情看MediaStore.Files). 文件也可以通过scanFile()方法插入到MediaStore中,有一点要注意的是一旦文件被添加到系统的MediaStore中该文件就可以被设备上所有的app访问了.

1.3 发送多段内容

要发送多段内容,就要使用ACTION_SEND_MULTIPLE这个action,然后将一系列的URI作为参数传到数据中,但是MIME类型就要看你的内容的类型而定.
如下示例:

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.."));

还是提醒下,要保证接收这些URI的应用有访问它们的权限.

2. 接收其他app发送的简单数据

正如app可以给其他的app发送数据一样,app也可以接收其他的app发送过来的数据,比如社交应用就会接收文本,图片或网址的数据。

2.1 更新Manifest

具体的在使用Intent来进行App间的基本交互中有描述,下面看示例代码:

<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>

2.2 处理接收的内容

当你用getIntent()方法拿到Intent对象后,就可检查intent中携带的内容然后做相应的处理,如下:

oid 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
    }
}

上述有两点需要注意:

  • 对intent的action和type的准确判断是非常重要的,特别是如上支持多种类型,因为你永远不知道其他app给你发送的数据是什么类型的.
  • 对于二进制数据的处理,记得要用异步.

3. 添加一个简单的分享功能

在Android 4.0(API 14)开始引入的ActionProvider之后,在ActionBar上面添加一个有效并友好的分享功能变得更简单了. 对于ActionProvider,一旦将它添加到ActionBar的menu的item中,它就会负责去处理试图的显示和事件的处理,比如ShareActionProvider,你只需要给它一个intent然后其他的它就会帮你完成.

3.1 更新Menu的声明

在menu的xml中,要使用ShareActionProvider,需要在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>

3.2 设置要分享的Intent

上述设置了ShareActionProvider之后,还需要给它提供一个Intent,具体如下:

private mShareActionProvider 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);
    }
}

通过上述代码之后,你还要在合适的地方调用setShareIntent()方法,并把构建的Intent对象传入,然后其他的事情就交给mShareActionProvider去处理就好了.

上述代码在运行时候可能会抛出一个异常:

java.lang.UnsupportedOperationException: This is not supported, use MenuItemCompat.getActionProvider()
...

原因:
这是因为用到的Activity继承的父类是v7包中的AppCompatActivity,从而在调用onCreateOptionsMenu()创建Menu时返回的也会是v7包中的MenuBuilder对象的引用,然后用该menu来调用findItem()方法返回的也会v7包中的MenuItemImpl对象的引用,而在MenuItemImpl中,getActionProvider()这个方法只会抛出一个上述异常(如下),其他什么都不做,这就是上述异常的原因.

package android.support.v7.view.menu;
...
public final class MenuItemImpl implements SupportMenuItem {
    ...
    @Override
    public android.view.ActionProvider getActionProvider() {
        throw new UnsupportedOperationException(
                "This is not supported, use MenuItemCompat.getActionProvider()");
    }
    ...
}

解决方法:
使用v7包中的ShareActionProvider. 具体步骤如下:

  1. menu的xml文件中:
 <item
        android:id="@+id/menu_share"
        android:title="@string/menu_share"
        support:actionProviderClass="android.support.v7.widget.ShareActionProvider"
        support:showAsAction="always" />
  1. 代码中:
import android.support.v7.widget.ShareActionProvider;
...
 // BEGIN_INCLUDE(get_sap)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu resource
        getMenuInflater().inflate(R.menu.main_menu, menu);

        // Retrieve the share menu item
        MenuItem shareItem = menu.findItem(R.id.menu_share);

        // Now get the ShareActionProvider from the item
        mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);

        ...
        return super.onCreateOptionsMenu(menu);
    }

Reference

  1. Sharing Simple Data
  2. Sending Simple Data to Other Apps
  3. Receiving Simple Data from Other Apps
  4. Adding an Easy Share Action
  5. MIME Media Types
  6. This is not supported, use MenuItemCompat.getActionProvider()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容