参考:
https://www.geek-share.com/detail/2631984744.html
https://tuzhao.org/article/34#directory0136555709956478031
感谢大佬将我从无思路的源码中解救出来
csdn实现文章页内跳转:
https://blog.csdn.net/qq_42292831/article/details/84680403
先写一下我的7.1.2源码分析的结论:
我认为假如可以启动一个Activity,这时这一个Activity对应的Intent通过addResolveInfo()赋值给了函数ResolverActivity.mOtherProfile,但是却并没有看到对mOtherProfile处理的地方,所以不知道没有给Intent.EXTRA_INITIAL_INTENTS赋值,只有一个Intent是怎么启动的??;
假如可启动5个Activity,这时对应的5个Intent标号为abcde,其中a会首先被拿出来,根据源码,[b,c,d,e]先执行addResolveInfo()函数,于是b先被赋值给ResolverActivity.mOtherProfile,cde被add到mDisplayList中;接着a也会通过调用addResolveInfo()被add到mDisplayList中;然后还会执行一次addResolveInfo()将b也add到mDisplayList中。所以这种是解释的通的。
断断续续地看了好久源码了,主要是这个mOtherProfile不知道它存在的意义是什么,直接把Intent给add到mDisplayList中不好吗?而且由于它的存在我也弄不懂启动一个Activity的逻辑,,,,,望也在看Intent.createChooser源码的有缘人看看我哪里分析错了,或者我们一起讨论一下。
用法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_share = findViewById(R.id.btn_share);
btn_share.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent intent= new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(intent, 0);
if(resolveInfos.isEmpty()) return;
List<Intent> targetIntents = new ArrayList<>();
for(ResolveInfo info : resolveInfos){
ActivityInfo ainfo = info.activityInfo;
switch(ainfo.packageName){
case "com.tencent.mm":
case "com.tencent.mobileqq":
case "com.sina.weibo":
addShareIntent(targetIntents, ainfo);
break;
}
}
if(targetIntents == null || targetIntents.size() == 0){
return;
}
Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), "分享至:");
if(chooserIntent == null){
return;
}
//List.toArray 将L在转换的时候将需要的类型当成参数传入,java工具即可给我们返回我们想要的类型。
//如果targetIntents为空的话,就只启动上面的那个targetIntents.remove(0)即可,不出现选择的框
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{
}));
startActivity(chooserIntent); // 启动的是Android源码中的action为 Intent.ACTION_CHOOSER 的activity
}
});
}
private void addShareIntent(List<Intent> list, ActivityInfo ainfo){
Intent target = new Intent(Intent.ACTION_SEND);
target.setType("text/plain");
target.putExtra(Intent.EXTRA_TEXT, "分享看看吧!");
target.setPackage(ainfo.packageName);
target.setClassName(ainfo.packageName, ainfo.name);
list.add(target);
}
}
安装了微信、qq,没有安装微博:
微信的两个界面:
com.tencent.mm.ui.tools.ShareImgUI
com.tencent.mm.ui.tools.AddFavoriteUI
来看下源码:
public static Intent createChooser(Intent target, CharSequence title) {
return createChooser(target, title, null);
}
public static final int FLAG_GRANT_READ_URI_PERMISSION = 0x00000001;
public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 0x00000002;
public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 0x00000040;
public static final int FLAG_GRANT_PREFIX_URI_PERMISSION = 0x00000080;
public static Intent createChooser(Intent target, CharSequence title, IntentSender sender) {
//创建了一个Action为ACTION_CHOOSER的Intent,这里我没有想到直接在Android源码中找ACTION_CHOOSER这个action
Intent intent = new Intent(ACTION_CHOOSER);
intent.putExtra(EXTRA_INTENT, target);
if (title != null) {
intent.putExtra(EXTRA_TITLE, title);
}
//-----null-----
if (sender != null) {
intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender);
}
// Migrate any clip data and flags from target.
int permFlags = target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION
| FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| FLAG_GRANT_PREFIX_URI_PERMISSION);
if (permFlags != 0) {
ClipData targetClipData = target.getClipData();
//-----不走这个if语句------
if (targetClipData == null && target.getData() != null) {
ClipData.Item item = new ClipData.Item(target.getData());
String[] mimeTypes;
if (target.getType() != null) {
mimeTypes = new String[] {
target.getType() };
} else {
mimeTypes = new String[] {
};
}
targetClipData = new ClipData(null, mimeTypes, item);
}
//-----null-----
if (targetClipData != null) {
intent.setClipData(targetClipData);
intent.addFlags(permFlags);
}
}
return intent;
}
由源码和我的代码可知,这里调用 Intent.createChooser 就给 intent 加了个:intent.putExtra(EXTRA_TITLE, title);
那么接下来再看看startActivity的代码(错误的思路:想看startActivity而没有想到看它起的是哪个Activity):
android.app.Activity.startActivity()
//参数值:chooserIntent
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
//参数1:chooserIntent
//参数2:null
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
//参数1:chooserIntent
//参数2:-1
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
//参数1:chooserIntent
//参数2:-1
//参数3:null
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
//mParent:https://www.jianshu.com/p/3141d2c0194c
//值为null
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
(正确的思路:查看Intent.createChooser()对应的是哪个Activity;忘记android studio可以调试了)
可以把启动的代码看为如下所示的:
Intent chooserIntent = new Intent(ACTION_CHOOSER);
chooserIntent.putExtra(EXTRA_INTENT, targetIntents.remove(0));
chooserIntent.putExtra(EXTRA_TITLE, title);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{
}));
startActivity(chooserIntent);
Android源码中的//device/apps/common/AndroidManifest.xml:
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.DeviceDefault.Resolver"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:documentLaunchMode="never"
android:relinquishTaskIdentity="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
android:process=":ui">
com.android.internal.app.ChooserActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT); //targetIntents.remove(0)
if (!(targetParcelable instanceof Intent)) {
··· ···
}
Intent target = (Intent) targetParcelable;
if (target != null) {
modifyTargetIntent(target); //给Intent添加Flags
}
mReplacementExtras = intent.getBundleExtra(Intent.EXTRA_REPLACEMENT_EXTRAS); //null
CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE); //"分享至:"
int defaultTitleRes = 0;
if (title == null) {
··· ···
}
Parcelable[] pa = intent.getParcelableArrayExtra