android系统分享分析Intent.createChooser

系统提供的分享实现代码如下:

Intent send = new Intent(Intent.ACTION_SEND);  
        send.setType("text/plain");  
        send.putExtra(Intent.EXTRA_TEXT, url);  
        send.putExtra(Intent.EXTRA_SUBJECT, title);    
        c.startActivity(Intent.createChooser(send, "share title"));

我们先扒一扒源码这个是怎么实现分享

  • Intent.ACTION_SEND很好理解,一个隐式intent的action,在这里调用会打开对应的暴漏出该action的app对应页面(可以自己写个app,然后暴漏该action 也会出现在分享列表中)
  • 剩下就是通过intent把分享参数title text add进去

重点扒一扒Intent.createChooser

  1. createChooser()方法new Intent(ACTION_CHOOSER),返回的是一个Intent对象,弹出的选择框是一个Activity,在源码中搜索一下Action为com.android.internal.app.ChooserActivity的Activity
/android/frameworks/base/core/res/AndroidManifest.xml  

  
              
                  
                  
              
        

  1. ChooserActivity调用了其父类ResolverActivity的OnCreate(),ResolverActivity相当于一个Activity的选择器,ChooserActivity在onCreate()方法里先获取传递进来的Intent对象,取得其中携带的目标Intent。如果只有一个Activity适配,将直接启动。 ResolverActivity(queryIntentActivities)就是这个选择对话框的Activity,这里获得适配Activity的icon和title等信息显示到对话框。如果没有调用createChooser()方法,如果有多个Activity适配一个intent的话也会打开一个选择对话框,不过这个对话框多了两个选项.

总结:这下大家应该清楚了,原来在调用createChooser()方法时候,系统又创建了一个新的Action为ACTION_CHOOSER的Intent ,并把我们的原始Intent当成了参数传进去 。选择器的title是通过 EXTRA_TITLE传入进去的。

Custom choose intent

产品或者我们自己这个分享列表提出自己的要求,比如是否可以监听这个列表点击自定义跳转、把facebook whatsapp这两个app放在第一个、或者某个app不要出现在分享列表中 等这些需求该如何实现;

  1. 监听这个列表点击自定义跳转操作 答案是 NO,弹框是系统的ChooserActivity,并不存在暴漏出列表item点击的监听回调,而且从隐式intent设计来讲,列表中的app都是与其暴漏出的intent对应匹配上的,它的初衷就是匹配上来就跳转。参考回答 想实现监听跳转只能自定义分享列表list adapter填充列表数据 跳转等,我们上个版本就是这样实现的。核心代码是获取能分享的列表数据

         Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
         sharingIntent.setType("text/plain");
         PackageManager pm = App.getInstance().getPackageManager();
         List> listArrayList = new ArrayList<>();
         List activityList = pm.queryIntentActivities(sharingIntent, 0);
         List newActivityList = new ArrayList<>();
    
         for (Iterator it = activityList.iterator(); it.hasNext(); ) {
             ResolveInfo info = it.next();
             //过滤出facebook google+  whatapp  分享app单独处理
             if (info.activityInfo.packageName.equals("com.facebook.katana") || info.activityInfo.packageName.equals("com.google.android.apps.plus") || info.activityInfo.packageName.equals("com.facebook.orca") || info.activityInfo.packageName.contains("whatsapp")) {
                 it.remove();
                 newActivityList.add(info);
             }
         }
    
    
  2. 从上面的核心代码看既然能实现分享列表数据的过滤,那么排序和删除数据都可以简单实现。但也必须是自己自定义分享弹框列表实现。上个版本就是这么做的

  3. 放google+分享列表实现(先谈一个BottomSheetDialog展示特异强调的分享app和一个other按钮,点other再进入系统的分享列表) 1.难点是用过滤的分享数据实现系统的分享。之前系统的分享数据是在ChooserActivity中自己匹配的。可喜的找到了Intent中EXTRA_INITIAL_INTENTS参数。具体看代码源码

         List targetIntents = new ArrayList();
         Intent shareIntent = new Intent(Intent.ACTION_SEND);
         shareIntent.setType("text/plain");
         for (ResolveInfo candidate : packages) {
             String packageName = candidate.activityInfo.packageName;
             Intent target = new Intent(android.content.Intent.ACTION_SEND);
             target.setType("text/plain");
             if (uri != null) {
                 shareIntent.setType("image/*");
                 shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
             }
             target.putExtra(Intent.EXTRA_TEXT, shareText);
             target.setComponent(new ComponentName(packageName, candidate.activityInfo.name));
    
             targetIntents.add(target);
         }
         Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), title);
         chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
         context.startActivity(chooserIntent);
    
    

最终展现给用户的选择包括,符合createChooser第一个参数的应用(其实是指定了packageName和className的Intent),以及由EXTRA_INITIAL_INTENTS指定的应用

疑问

  1. 注意,这里没有使用Intent.setComponent来明确指定要启动的Activity,而是通过setPackageName和setClass来指定。这是因为,在createChooser处理过程中,第一个参数intent指定的component会在ResolverActivity中强制被设置为null。这样的结果是什么呢?当component被设置为null后,targetIntents.remove(0)其实就是emailIntent,那么createChooser会显示所有满足emailIntent的应用,然后在加上由EXTRA_INITIAL_INTENTS指定的应用。你会发现选择界面中出现了重复的应用。

2.过滤数据处理后的系统分享弹框,与原声系统分享弹框少了下面两个按钮,也少了上面最佳常用app的列表

你可能感兴趣的:(android系统分享分析Intent.createChooser)