Content Sharing——Sharing Simple Data

       本课程教你如何产生一个在app和设备间共享数据的app。          

        Sharing Simple Data

        Sharing Files

        Sharing Files with NFC

        

       Sharing Simple Data

         Android应用最伟大之处之一就是不同应用间的通信和整合的能力。如果一个功能在其他的app里已经实现了,而这些功能并不是你的app的“主业”,为什么自己再重新实现这些功能呢? 

        本文讲述几种方式用来在不同的应用之间使用Intent API和ActionProvider 对象发送和接收简单数据。   

     Lessons

          Sending Simple Data to Other Apps

        学习如何通过Intent从你的application向其他的application发送文本和二进制数据

        Receiving Simple Data from Other Apps

        学习如何在你的application里获取从intent里传入的文本和二进制数据

         Adding an Easy Share Action

        学习如何在你的Action Bar里添加“share” action 条目

        Sending Simple Data to Other Apps

       当你构建一个intent时,你必须指定你想要该intent触发的action。Android定义了许多action,例如ACTION_SEND,该action表明intent从一个activity向另一个activity传递数据,甚至在不同进程间传递数据。为了向另一个activity发送数据,你需要做的是指定数据和类型,系统会识别能处理该intent的所有activity,然后将这些activity展示给用户(当不止一个activity时)或者立即的开启一个activity(如果仅仅有一个能处理的activity时)。相似地,你能在你的manifest文件里定义数据类型以表明你的activity能接收和处理来自其他application的哪些intent。

        在不同application之间使用intent来发送和接收数据是最常见和通用的内容共享方式。Intent能让用户很快很容易的共享信息。

        注:在ActionBar里添加一个共享action item的最好的方式是使用ShareActionProvider,该类在API 14及以上版本中才可用。

       

      Send Text Content

         ACTION_SEND action最直接和最通用的方式是从一个activity到另一个activity发送文本内容。例如,内建浏览器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和MIME类型为text/plain的过滤器,Android系统将运行和启动该应用。如果不止一个app匹配,系统展示多选对话框(“chooser”)来让用户选择一个app。

      

        然而,如果你调用Intent.createChooser(),传递给你的intent对象,该调用将返回你的intent的版本,总是展示该chooser。这样有一些优点:

  • 即使用户先前已选择了一个默认的ACTION来处理该intent,chooser仍然将会展示给用户。
  • 如果没有匹配的app,Android展示系统消息。
  • 你能为chooser对话框指定一个title。

        下面是更新了的代码:

       

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

        结果对话框如下图一所示:

        

 Figure 1. Screenshot of ACTION_SENDintent chooser on a handset.

        还有一些其他的标准的extras: EXTRA_EMAILEXTRA_CCEXTRA_BCCEXTRA_SUBJECT如果接收application不使用它们,系统简单地忽略它们。

        注:一些email应用,例如Gmail,需要一个字符串数组String[] 给extras,例如 EXTRA_EMAIL  和  EXTRA_CC, 可以使用putExtra(String, String[]) 加这些到你的intent。    

      Send Binary Content

         共享二进制数据也是使用ACTION_SEND action,需要设置合适的MIME类型,和添加URI到extra的数据里,该URI名叫EXTRA_STREAM这通常用于共享图片数据,但也能共享任何类型的二进制内容。

        

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)));
         注意如下几点:
  • 你能使用"*/*"作为MIME类型,但是这将仅仅匹配能处理一般数据流的activity。
  • 响应app需要访问URi指向数据的权限。推荐如下方式实现:
  1. 在你自己的ContentProvider存储数据 ,确保其他的app有相应的权限访问你的provider。更好的提供的访问机制是使用per-URI permissions ,该权限是临时的,仅仅保证对响应app的访问。一个容易的方式是使用FileProvider帮助类产生一个ContentProvider。
  2. 使用系统MediaStore.MediaStore其主要目的是用于视频、音频和图片MIME类型,然而,从Android3.0(API11)开始,该类也用于存储非媒体类型(seeMediaStore.Files for more info)的数据。文件。文件能通过 scanFile()插入MediaStore。在after which acontent:// style Uri suitable for sharing is passed to the provided onScanCompleted() callback。注意:一旦加入到系统MediaStore,设备上的任何app都能访问存储在MediaStore里的数据。         

       Send Multiple Pieces of Content

          为了共享多部分内容,使用ACTION_SEND_MULTIPLE action配合一组指向内容的URIs。MIME类型依据你共享的内容而定。例如,如果你共享3个JPEG图片,MIME类型仍然是”image/jpeg“.例如如果是各种格式的图片,类型应该是”image/*",如果你正共享的是各种类型的数据,你应该使用“*/*”        像先前描述的,这决定了哪些app解析和处理你的数据。下面是一个例子:

        

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

         像先前所说的,确保提供的URIs指向的数据能被相应的app访问。

         

       Receiving Simple Data from Other Apps

         你的app能发送数据给其他的应用,当然,你的app也能接收来自其他app的数据。想想用户怎么和你的app交互,以及你想要从其他的app接收什么类型的数据。例如,一个社交app很可能需要接收文本内容,如来自于其他app的一个感兴趣的web URL数据。Google+ Android application既可以接收文本也可以接收图片数据。      

      Update Your Manifest

        意图过滤器通知系统某个app的组件将接受什么意图。类似于Sending Simple Data to Other Apps这节讲的如何使用action ACTION_SEND 构造Intent,为了能接受intent,你能使用该action产生意图过滤器。你在你的manifest里使用<intent-filter> 元素定义意图过滤器。如果你的app想要处理文本类型、一种或者多种图片格式的数据,你的manifest应该如下:

        

<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>
         注:更多的关于意图过滤器和意图的介绍请看见 Intents and Intent Filters

        当另一个app通过构造一个intent试图共享如上manfest定义的数据,然后传递该intent给startActivity()时,你的app将在intent chooser里作为一个选项被列出。如果用户选择你的app,响应的activity(对应上面例子中的.ui.MyActivity)将被调起。然后由你确定在你的代码和UI里如何处理传递过来的数据。

      

      Handle the Incoming Content

        为了处理一个intent投递过来的数据,首页调用getIntent() 得到该Intent对象。一旦你有了该对象,你能检查它里面的内容以决定接下来如何做。记住,如果activity能被系统的其他部分(例如launcher)调起,那么当你检查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
    }
}

         注意:需要特别关注对传入的数据进行check。你不能知道一些其他的app将送你什么数据。例如,传递过来的intent里可能设置了错误的MIME类型,或者发送过来的image可能极其的大。还要记住,在单独的线程而不是主线程(UI线程)处理二进制数据。

        有些UI更新可能很简单,像填充EditText一样,也有像更新图片这样的复杂的UI更新,收到数据后怎么处理和更新UI因app而异。

        

      Adding an Easy Share Action

        通过使用Android4.0(API 14)里介绍的ActionProvider能在ActionBar里容易的实现一个有效的、用户友好的共享action。ActionProvider,一旦附件到actionbar里的某天menu item,既能处理该item的展示也能该item的行为。以ShareActionProvider为例,你提供一个共享intent,剩下的事由它来做。

       注:ShareActionProvider在API 14或者更高的版本才有效。

      Update Menu Declarations    

        为了能使用ShareActionProvider,在你的menu resource 文件的相应<item>定义android: action ProviderClass属性:       

<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处理item的展现和功能。然而,你需要告诉provider你想要share什么。

        

 Figure 1. TheShareActionProvider in the Gallery app.    

     Set the Share Intent

        为了ShareActionProvider有效,你必须提供share intent给它。这共享intent应该和Sending Simple Data to Other Apps节里描述的相似,action为ACTION_SEND,通过extras设置EXTRA_TEXT和EXTRA_STREAM额外的数据。为了指派共享intent,首先当在Activity或者Fragment里渲染你的menu资源时找到相应的MenuItem。接下来,调用MenuItem.getActionProvider() 方法检索ShareActionProvider实例。使用 setShareIntent() 更新相关联的action item的共享意图。如下是例子:

        

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

        你可能只需要在menu产生期间设置share action一次,或者你可能当UI改变时设置或者更新它。例如,当你在Gallery app里全屏浏览照片时,share action当你在照片间滑动时改变。

        更多关于ShareActionProvider 对象的讨论,参见 Action Bar guide。

猜你喜欢

转载自xhmj12.iteye.com/blog/2085730