Intent.createChooser方法源码解析(按我的解析,只有一个Intent是不会启动的??Android源码7.1.2)

参考:
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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android IntentAndroid系统中常用的组件之一,它用于在不同的组件之间传递消息和数据。在使用Intent时,常用的参数包括Action、Category、Data、Type和Extra等。其中,Extra是Intent中比较重要的一种参数,用于传递数据。 Extra的具体用法如下: 1. putExtra方法 使用putExtra方法Intent中添加参数。putExtra方法有多个重载版本,可以传递不同类型的数据,如字符串、整数、布尔值、字符数组、字节数组等。例如: ``` Intent intent = new Intent(); intent.putExtra("name", "张三"); intent.putExtra("age", 18); startActivity(intent); ``` 2. getExtra方法 使用getExtra方法Intent中获取参数。getExtra方法也有多个重载版本,需要根据传递数据的类型来选择相应的方法。例如: ``` Intent intent = getIntent(); String name = intent.getStringExtra("name"); int age = intent.getIntExtra("age", 0); ``` 其中,getIntExtra方法的第二个参数表示如果获取不到对应的值,则返回默认值0。 3. Bundle参数 使用Bundle参数可以在Intent中传递更复杂的数据结构,如数组、集合等。例如: ``` Intent intent = new Intent(); Bundle bundle = new Bundle(); String[] names = {"张三", "李四", "王五"}; bundle.putStringArray("names", names); intent.putExtras(bundle); startActivity(intent); ``` 在接收方,使用getExtras方法获取Bundle参数,再根据键值获取对应的数据。例如: ``` Intent intent = getIntent(); Bundle bundle = intent.getExtras(); String[] names = bundle.getStringArray("names"); ``` 4. Parcelable参数 Parcelable参数可以用于在Intent中传递自定义对象。自定义对象需要实现Parcelable接口,并重写相应的方法。例如: ``` public class Person implements Parcelable { private String name; private int age; // 省略构造方法和其他方法 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { @Override public Person createFromParcel(Parcel in) { return new Person(in); } @Override public Person[] newArray(int size) { return new Person[size]; } }; private Person(Parcel in) { name = in.readString(); age = in.readInt(); } @Override public int describeContents() { return 0; } } ``` 在使用Intent传递自定义对象时,需要使用putExtra方法,并将自定义对象作为参数传递。例如: ``` Intent intent = new Intent(); Person person = new Person("张三", 18); intent.putExtra("person", person); startActivity(intent); ``` 在接收方,使用getParcelableExtra方法获取Parcelable参数。例如: ``` Intent intent = getIntent(); Person person = intent.getParcelableExtra("person"); ``` 以上就是Android Intent中Extra参数的几种用法。在实际开发中,Extra参数可以用于在不同的Activity、Service和BroadcastReceiver之间传递数据,非常方便。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值