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

我們先扒一扒源碼這個是怎麼實現分享

public static Intent createChooser(Intent target, CharSequence title) {
	Intent intent = new Intent(ACTION_CHOOSER);
	intent.putExtra(EXTRA_INTENT, target);
	if (title != null) {
		intent.putExtra(EXTRA_TITLE, title);
	}
	return intent;
}
  • 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  

<activity android:name="com.android.internal.app.ChooserActivity"  
                android:theme="@style/Theme.Holo.Dialog.Alert"  
                android:finishOnCloseSystemDialogs="true"  
                android:excludeFromRecents="true"  
                android:multiprocess="true">  
            <intent-filter>  
                <action android:name="android.intent.action.CHOOSER" />  
                <category android:name="android.intent.category.DEFAULT" />  
            </intent-filter>  
        </activity>

  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<List<ResolveInfo>> listArrayList = new ArrayList<>();
     List<ResolveInfo> activityList = pm.queryIntentActivities(sharingIntent, 0);
     List<ResolveInfo> newActivityList = new ArrayList<>();

     for (Iterator<ResolveInfo> 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);
         }
     }
  • 從上面的核心代碼看既然能實現分享列表數據的過濾,那麼排序和刪除數據都可以簡單實現。但也必須是自己自定義分享彈框列表實現。上個版本就是這麼做的

  • 放google+分享列表實現(先談一個BottomSheetDialog展示特異強調的分享app和一個other按鈕,點other再進入系統的分享列表) 1.難點是用過濾的分享數據實現系統的分享。之前系統的分享數據是在ChooserActivity中自己匹配的。可喜的找到了Intent中EXTRA_INITIAL_INTENTS參數。具體看代碼源碼

  •      List<Intent> targetIntents = new ArrayList<Intent>();
         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的列表

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章