Intent这个东西

Intent这个东西

 

 

Intent学名:意图,主要用于android应用的各个组件之间的通讯。它包含发生请求的组件中的一组信息送给被请求的对象。你可以想象它是快递员,它携带了各中“物件“给客户。

要寄快递,我们得先打电话。拿起你的Android手机,按下拨号键盘的时候你的android手机做了些什么?“意图“有用吗?

 

按下按键这个动作后


    public void dialButtonPressed() {
        if (isDigitsEmpty()) { // No number entered.
            handleDialButtonClickWithEmptyDigits();
        } else {
            final String number = mDigits.getText().toString();

            // "persist.radio.otaspdial" is a temporary hack needed for one carrier's automated
            // test equipment.
            // TODO: clean it up.
            if (number != null
                    && !TextUtils.isEmpty(mProhibitedPhoneNumberRegexp)
                    && number.matches(mProhibitedPhoneNumberRegexp)
                    && (SystemProperties.getInt("persist.radio.otaspdial", 0) != 1)) {
                Log.i(TAG, "The phone number is prohibited explicitly by a rule.");
                if (getActivity() != null) {
                    DialogFragment dialogFragment = ErrorDialogFragment.newInstance(
                            R.string.dialog_phone_call_prohibited_message);
                    dialogFragment.show(getFragmentManager(), "phone_prohibited_dialog");
                }

                // Clear the digits just in case.
                mDigits.getText().clear();
            } else {
		// 省略前面100字,看这里已经叫到“快递员“Intent了,快递员拿着电话号码“number“ 去送给DialtactsActivity.EXTRA_CALL_ORIGIN这个家伙
                final Intent intent = ContactsUtils.getCallIntent(number, /*s1*/
                        (getActivity() instanceof DialtactsActivity ?
                                ((DialtactsActivity)getActivity()).getCallOrigin() : null));
                startActivity(intent);
                mClearDigitsOnStop = true;
                getActivity().finish();
            }
        }
    }
	

    public static Intent getCallIntent(String number, String callOrigin) {/*s2*/
        return getCallIntent(getCallUri(number), callOrigin);
    }


    public static Intent getCallIntent(Uri uri, String callOrigin) {/*s3*/
        final Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (callOrigin != null) {
            intent.putExtra(DialtactsActivity.EXTRA_CALL_ORIGIN, callOrigin);
        }
        return intent;
    }

 

完成了一次送递!

哦!Intent原来就是这样用。温故而之新,这也是启动Activity的例子。其实Intent不但可以启动Activity,他还可以启动Service 、Broadcast 这些组建。

小结一下:

intnet 勾搭了 activity  方式:startActivity() ,startActivityForResult()

intnet 勾搭了 service   方式:startService() ,bindService()

intnet 勾搭了 broadcast 方式: sendBroadcast(), sendOrderedBroadcast(), or sendStickyBroadcast()

<think>我们正在讨论的是使用特定的Intent标志(FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK)来启动Activity时,是否能够确保新建一个任务栈(Task Stack)。 根据Android官方文档和实际行为: 1. **FLAG_ACTIVITY_NEW_TASK**: - 此标志的通常行为是:当启动一个Activity时,会检查是否存在与该Activity关联的任务栈(通过taskAffinity属性指定,默认为应用包名)。如果不存在,则新建一个任务栈并将Activity放入;如果存在,则将该任务栈带到前台,并根据情况决定是否新建Activity实例。 - 但是,单独使用`FLAG_ACTIVITY_NEW_TASK`并不保证一定会新建任务栈,因为如果已有对应任务栈,则不会新建。 2. **FLAG_ACTIVITY_CLEAR_TASK**: - 此标志必须与`FLAG_ACTIVITY_NEW_TASK`一起使用。 - 它的作用是:在将Activity放入任务栈之前,清除与Activity关联的整个任务栈(即移除该任务栈中所有已有的Activity)。然后新建一个该Activity的实例作为任务栈的根Activity。 - 因此,使用`FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK`组合时,会确保先清除与该Activity关联的现有任务栈(如果存在的话),然后新建一个任务栈,并将该Activity的新实例作为根Activity放入。 3. **新建任务栈的保证**: - 使用`FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK`组合,确实会确保新建一个任务栈(因为先清除原有的,再新建一个)。但是注意,这个新建的任务栈的affinity由被启动的Activity的taskAffinity决定。如果该Activity没有显式指定taskAffinity,则使用默认的(应用包名)。 4. **特殊情况**: - 如果之前没有与该Activity相同affinity的任务栈,那么`FLAG_ACTIVITY_CLEAR_TASK`就没有东西可清除,但组合标志仍然会新建一个任务栈。 因此,结论是:**使用`Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK`启动Activity,能够确保新建一个任务栈(即一个新的Task),并将该Activity作为根Activity放入这个新任务栈中。** 但是,请注意以下几点: - 在快速连续启动的情况下,由于系统处理任务栈需要时间,可能会出现前一个任务栈尚未完全销毁,后一个启动请求已经到达的情况。此时,系统可能会复用正在销毁的任务栈(尽管我们期望新建),从而导致Activity实例被复用(即不会走`onCreate`而是走`onNewIntent`)。这就是之前问题中提到的“有概率不走onCreate”的原因。 验证方法: - 在启动Activity后,可以通过`getTaskId()`获取当前任务栈的ID,然后比较每次启动后的任务栈ID是否不同(如果不同,则说明是新建的任务栈)。 - 或者通过ADB命令查看任务栈状态:`adb shell dumpsys activity activities`。 因此,虽然组合标志会要求新建任务栈,但在极端快速连续启动的情况下,由于系统异步处理任务栈的销毁和创建,可能会出现复用的情况(表现为任务栈ID相同)。但正常情况下,每次启动都会新建任务栈。 引用说明: - 引用[1]提到使用`FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK`来开始新的activity同时移除之前所有的activity,这符合我们的结论。 - 引用[2]展示了另一种组合(包含`CLEAR_TOP`),但我们的关注点在于`NEW_TASK`和`CLEAR_TASK`组合。 - 引用[3]解释了标记位的含义,其中提到`FLAG_ACTIVITY_NEW_TASK`指定为SingleTask模式(实际上,在标志位中,`FLAG_ACTIVITY_NEW_TASK`并不等同于SingleTask,但有一些相似之处),而`FLAG_ACTIVITY_CLEAR_TOP`会移除上面的Activity,而`CLEAR_TASK`则会清除整个任务栈。 - 引用[4]展示了代码示例,其中使用了`NEW_TASK|CLEAR_TASK`,并且还加上了`killProcess`和`System.exit(0)`,这是为了完全退出应用,但通常我们并不需要这样做,因为标志组合已经可以清除之前的Activity。 总结回答: 使用`Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK`启动Activity,系统会确保为目标Activity创建一个新的任务栈(Task),并将该Activity作为根Activity放入。但要注意在快速连续启动时可能因系统异步处理导致复用任务栈(此时不会调用`onCreate`而是调用`onNewIntent`)。 相关问题: 1. 在什么情况下使用`FLAG_ACTIVITY_CLEAR_TASK`而不使用`FLAG_ACTIVITY_NEW_TASK`? 2. 如何防止快速连续启动Activity导致的任务栈复用问题? 3. 使用`FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK`时,如何确保每次启动都调用`onCreate`? 4. 任务栈(Task)和返回栈(Back Stack)有什么区别?</think>### 使用 `FLAG_ACTIVITY_NEW_TASK` 和 `FLAG_ACTIVITY_CLEAR_TASK` 能否确保新建任务栈? #### ✅ 核心结论 **使用 `Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK` 组合能确保新建任务栈**,但需注意特殊场景下的行为差异: 1. **新建任务栈的保证** 该标志组合会强制系统执行: - 清除与目标 Activity 关联的**整个现有任务栈**(包括所有 Activity) - 创建**全新的任务栈** - 将目标 Activity 作为新任务栈的**根 Activity** 启动 ```java // 保证新建任务栈的标准写法 Intent intent = new Intent(context, TargetActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); context.startActivity(intent); ``` 2. **特殊场景说明** | 场景 | 是否新建任务栈 | 说明 | |-------------------------------|----------------|----------------------------------------------------------------------| | **首次启动** | ✅ 是 | 必然创建新任务栈 | | **已有同affinity任务栈** | ✅ 是 | 先完全销毁旧栈再建新栈 | | **快速连续启动** | ⚠️ 可能复用 | 旧栈未完全销毁时可能复用(此时走`onNewIntent`而非`onCreate`)[^1] | | **跨应用启动** | ✅ 是 | 始终在新任务栈中启动 | --- #### 🔍 关键验证方法 1. **任务栈 ID 检测** 在目标 Activity 中输出任务栈 ID: ```java // 在onCreate()或onNewIntent()中调用 Log.d("TASK_DEBUG", "任务栈ID: " + getTaskId()); ``` - **新建任务栈** → 每次启动 ID 不同 - **复用任务栈** → 连续启动时 ID 相同 2. **ADB 命令验证** ```bash adb shell dumpsys activity activities | grep -E 'TaskRecord|Hist #' ``` 观察输出中: - `numActivities=1` 表示新栈 - 目标 Activity 显示 `root=xxx` --- #### ⚠️ 注意事项 1. **Affinity 的影响** 任务栈由 Activity 的 `taskAffinity` 属性决定: ```xml <activity android:name=".TargetActivity" android:taskAffinity="com.example.custom_stack"/> ``` - 相同 affinity 的 Activity 会分配到同一任务栈 - 默认 affinity = 应用包名 2. **与 `CLEAR_TOP` 的区别** | 标志组合 | 行为 | |-------------------------------------|----------------------------------------------------------------------| | `NEW_TASK | CLEAR_TASK` | 销毁整个旧栈,建全新栈 | | `NEW_TASK | CLEAR_TOP` | 保留任务栈,仅清除目标 Activity 之上的 Activity(可能复用实例)[^3] | | `NEW_TASK | CLEAR_TOP | CLEAR_TASK` | 等价于 `NEW_TASK | CLEAR_TASK` | 3. **快速启动问题的解决** 若需绝对避免复用: ```java // 强制新建实例(即使旧栈未完全销毁) intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); ``` > **代价**:可能创建多个相同任务栈(需配合 `android:launchMode="singleInstance"`) --- #### 💡 最佳实践 ```java // 确保每次都是全新任务栈的完整方案 public void launchWithNewTaskStack(Context context) { Intent intent = new Intent(context, MainActivity.class); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK // 防复用 ); context.startActivity(intent); // 可选:关闭旧Activity防止闪烁 if (context instanceof Activity) { ((Activity) context).finish(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值