系統(tǒng)提供的分享實(shí)現(xiàn)代碼如下:
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"));
我們先扒一扒源碼這個(gè)是怎么實(shí)現(xiàn)分享
- Intent.ACTION_SEND很好理解,一個(gè)隱式intent的action,在這里調(diào)用會(huì)打開(kāi)對(duì)應(yīng)的暴漏出該action的app對(duì)應(yīng)頁(yè)面(可以自己寫(xiě)個(gè)app胳赌,然后暴漏該action 也會(huì)出現(xiàn)在分享列表中)
- 剩下就是通過(guò)intent把分享參數(shù)title text add進(jìn)去
重點(diǎn)扒一扒Intent.createChooser
- createChooser()方法new Intent(ACTION_CHOOSER)司致,返回的是一個(gè)Intent對(duì)象惧浴,彈出的選擇框是一個(gè)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>
- ChooserActivity調(diào)用了其父類(lèi)ResolverActivity的OnCreate(),ResolverActivity相當(dāng)于一個(gè)Activity的選擇器烟逊,ChooserActivity在onCreate()方法里先獲取傳遞進(jìn)來(lái)的Intent對(duì)象,取得其中攜帶的目標(biāo)Intent铺根。如果只有一個(gè)Activity適配宪躯,將直接啟動(dòng)。 ResolverActivity(queryIntentActivities)就是這個(gè)選擇對(duì)話框的Activity位迂,這里獲得適配Activity的icon和title等信息顯示到對(duì)話框访雪。如果沒(méi)有調(diào)用createChooser()方法,如果有多個(gè)Activity適配一個(gè)intent的話也會(huì)打開(kāi)一個(gè)選擇對(duì)話框掂林,不過(guò)這個(gè)對(duì)話框多了兩個(gè)選項(xiàng).
總結(jié):這下大家應(yīng)該清楚了臣缀,原來(lái)在調(diào)用createChooser()方法時(shí)候,系統(tǒng)又創(chuàng)建了一個(gè)新的Action為ACTION_CHOOSER的Intent ,并把我們的原始Intent當(dāng)成了參數(shù)傳進(jìn)去 泻帮。選擇器的title是通過(guò) EXTRA_TITLE傳入進(jìn)去的精置。
Custom choose intent
產(chǎn)品或者我們自己這個(gè)分享列表提出自己的要求,比如是否可以監(jiān)聽(tīng)這個(gè)列表點(diǎn)擊自定義跳轉(zhuǎn)锣杂、把facebook whatsapp這兩個(gè)app放在第一個(gè)脂倦、或者某個(gè)app不要出現(xiàn)在分享列表中 等這些需求該如何實(shí)現(xiàn);
-
監(jiān)聽(tīng)這個(gè)列表點(diǎn)擊自定義跳轉(zhuǎn)操作 答案是 NO,彈框是系統(tǒng)的ChooserActivity,并不存在暴漏出列表item點(diǎn)擊的監(jiān)聽(tīng)回調(diào)元莫,而且從隱式intent設(shè)計(jì)來(lái)講狼讨,列表中的app都是與其暴漏出的intent對(duì)應(yīng)匹配上的,它的初衷就是匹配上來(lái)就跳轉(zhuǎn)柒竞。參考回答 想實(shí)現(xiàn)監(jiān)聽(tīng)跳轉(zhuǎn)只能自定義分享列表list adapter填充列表數(shù)據(jù) 跳轉(zhuǎn)等政供,我們上個(gè)版本就是這樣實(shí)現(xiàn)的。核心代碼是獲取能分享的列表數(shù)據(jù)
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(); //過(guò)濾出facebook google+ whatapp 分享app單獨(dú)處理 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); } }
從上面的核心代碼看既然能實(shí)現(xiàn)分享列表數(shù)據(jù)的過(guò)濾朽基,那么排序和刪除數(shù)據(jù)都可以簡(jiǎn)單實(shí)現(xiàn)布隔。但也必須是自己自定義分享彈框列表實(shí)現(xiàn)。上個(gè)版本就是這么做的
-
放google+分享列表實(shí)現(xiàn)(先談一個(gè)BottomSheetDialog展示特異強(qiáng)調(diào)的分享app和一個(gè)other按鈕稼虎,點(diǎn)other再進(jìn)入系統(tǒng)的分享列表) 1.難點(diǎn)是用過(guò)濾的分享數(shù)據(jù)實(shí)現(xiàn)系統(tǒng)的分享衅檀。之前系統(tǒng)的分享數(shù)據(jù)是在ChooserActivity中自己匹配的■可喜的找到了Intent中EXTRA_INITIAL_INTENTS參數(shù)哀军。具體看代碼源碼
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);
最終展現(xiàn)給用戶(hù)的選擇包括沉眶,符合createChooser第一個(gè)參數(shù)的應(yīng)用(其實(shí)是指定了packageName和className的Intent),以及由EXTRA_INITIAL_INTENTS指定的應(yīng)用
疑問(wèn)
- 注意杉适,這里沒(méi)有使用Intent.setComponent來(lái)明確指定要啟動(dòng)的Activity谎倔,而是通過(guò)setPackageName和setClass來(lái)指定。這是因?yàn)樵惩疲赾reateChooser處理過(guò)程中片习,第一個(gè)參數(shù)intent指定的component會(huì)在ResolverActivity中強(qiáng)制被設(shè)置為null。這樣的結(jié)果是什么呢?當(dāng)component被設(shè)置為null后蹬叭,targetIntents.remove(0)其實(shí)就是emailIntent藕咏,那么createChooser會(huì)顯示所有滿(mǎn)足emailIntent的應(yīng)用,然后在加上由EXTRA_INITIAL_INTENTS指定的應(yīng)用秽五。你會(huì)發(fā)現(xiàn)選擇界面中出現(xiàn)了重復(fù)的應(yīng)用孽查。
2.過(guò)濾數(shù)據(jù)處理后的系統(tǒng)分享彈框,與原聲系統(tǒng)分享彈框少了下面兩個(gè)按鈕坦喘,也少了上面最佳常用app的列表