关于startActivityForResult()方法后Activity直接退出的问题原因和解决办法

本文分析了使用startActivityForResult()启动Activity后出现应用退出的现象,并探讨了可能的原因,涉及activity1调用activity2的情景。通过详细步骤解释如何排查和解决此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现象:

今天在做调用相机拍照然后进行一些裁剪后显示的Demo。大题思路就是这样
	private final View.OnClickListener onClickListener = new View.OnClickListener() {

		@Override
		public void onClick(View v) {
			if(v==btnPhone){ //从相册获取图片
				Intent intent = new Intent(Intent.ACTION_PICK, null);
				intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
						IMAGE_UNSPECIFIED);
				startActivityForResult(intent, PHOTO_ZOOM);
			}else if(v==btnTakePicture){ //从拍照获取图片
				Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
				intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(
						new File(Environment
								.getExternalStorageDirectory(),"temp.jpg")));
				startActivityForResult(intent, PHOTO_GRAPH);
			}

		}

	};

直接根据用户 的选择调用安卓本身的一些功能就好了

通过startActivityForResult()方法在处理完成后回调到我们这个activity就好了 很简单
但是却遇到了一个问题 就是处理完成后activity直接退出了 通过Log发现startActivityForResult根本没有被执行到
这是怎么回事呢?

原因:

   假设有activity1和activity2, activity1调用activity2

1. activity1是SingleTask模式 也就是不在前台的时候就自动被销毁了 
自然不能接收到activity2的数据 也就呈现出了直接退出的现象

    解决方法:改成标准模式
2. setResult的第一个参数对应上面onActivityResult的第二个参数,注意别把onActivityResult的第一个参数与第二个参数搞混淆了,一个是请求标记,一个是返回标记。
 解决办法:分清楚就好了 没啥好说的
3. 最近在华为的手机上面发现Activity调用startActivityForResult后返回结果时,调用的Activity都会被重新创建,也就是Activity被销毁了。 在网上经过一番查找,发现有哥们说在手机开发人员选项里面有这么一项“不保留活动”被勾上了, 一看还真是。 把那个勾去掉一切又恢复正常了。
      这个是百度到的
   










<think>我们面对的问题:在Android开发中,当退出某个Activity时执行特定逻辑(如显示弹窗)的方法。 根据引用内容,我们可以考虑以下几种方式: 1. 在Activity的生命周期方法中(如onDestroy)执行逻辑并显示弹窗。但要注意,直接显示弹窗可能会因为Activity正在销毁而导致问题。 2. 使用DialogFragment来显示弹窗,因为FragmentManager可以管理DialogFragment,并且可以避免窗口泄漏等问题(引用[1]提到在onCreate或onResume中显示,但我们在退出时显示,所以需要选择合适时机)。 3. 注意回退栈(Back Stack)的概念(引用[2]),当Activity退出时,它会被从回退栈中移除。 然而,在退出Activity时(例如按下返回键或者调用finish()),我们通常会在onPause()、onStop()或onDestroy()中执行逻辑。但是,在这些方法直接显示弹窗是不合适的,因为: - Activity可能已经不再与用户交互(onPause之后),此时显示弹窗会抛出异常(无法添加窗口——token已经无效)。 - 在onDestroy中,窗口已经被销毁。 因此,我们可以考虑以下方案: 方案1:在调用finish()之前先显示弹窗,然后根据弹窗的结果再决定是否真正退出(比如弹窗是确认退出吗?)。但注意,如果用户按返回键退出,我们需要拦截返回键。 方案2:使用一个透明的Activity来显示弹窗,这样就不会有Activity被销毁导致弹窗消失的问题(引用[3]提到用Activity实现弹窗)。我们可以启动一个透明主题的Activity,在这个Activity中显示弹窗。当原Activity退出时,启动这个透明Activity,然后在这个透明Activity中显示弹窗。 方案3:使用一个全局的弹窗管理类,在Application级别显示弹窗,但需要注意权限上下文。 根据引用[3]中的例子,有人使用Activity来实现弹窗效果。我们可以借鉴这个思路。 具体步骤(以方案2为例): 1. 创建一个透明主题的Activity(比如命名为DialogActivity)。 2. 在需要退出Activity并显示弹窗的地方,启动DialogActivity(在启动之前,原Activity可以finish自己)。 3. 在DialogActivity中,在onCreate中设置弹窗内容(可以是DialogFragment,也可以是其他视图)。 但是,我们需要注意的是,原Activity退出后,我们启动一个透明的Activity来显示弹窗,这样用户感觉弹窗是从原Activity退出的,但实际上原Activity已经不存在了。 另外,如果用户按返回键退出Activity,我们可以在onBackPressed()中拦截,然后启动DialogActivity,并finish原Activity。 下面我们给出一个示例: 步骤1:定义透明主题 在styles.xml中添加一个透明主题: ```xml <style name="Theme.Transparent" parent="Theme.AppCompat.Dialog"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> <item name="android:backgroundDimEnabled">false</item> </style> ``` 步骤2:在AndroidManifest.xml中为DialogActivity设置透明主题 ```xml <activity android:name=".DialogActivity" android:theme="@style/Theme.Transparent" android:excludeFromRecents="true" android:taskAffinity="" android:launchMode="singleTask"/> ``` 步骤3:在需要退出并显示弹窗的Activity中(例如MainActivity),重写onBackPressed()方法,在用户按返回键时启动DialogActivity并结束自身。 ```java @Override public void onBackPressed() { // 启动DialogActivity Intent intent = new Intent(this, DialogActivity.class); startActivity(intent); // 结束当前Activity finish(); } ``` 步骤4:在DialogActivity中显示弹窗 ```java public class DialogActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 注意:这里我们不需要setContentView,而是使用DialogFragment来显示弹窗 // 创建并显示弹窗 MyDialogFragment dialogFragment = new MyDialogFragment(); dialogFragment.show(getSupportFragmentManager(), "dialog_tag"); // 设置弹窗关闭时结束Activity dialogFragment.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { finish(); } }); } } ``` 步骤5:定义MyDialogFragment 这个DialogFragment负责显示具体的弹窗内容。注意在onDismiss中通知Activity结束。 但是,上面的代码中,我们在DialogFragment中设置了一个OnDismissListener,当弹窗被取消时,DialogActivity会finish自己。 这个方案的好处是,弹窗显示在一个独立的Activity中,不受原Activity生命周期的影响。 但是,需要注意的是,如果原Activity是通过其他方式退出的(比如调用finish()),我们可能需要在所有退出点都启动DialogActivity。这可能会变得复杂。 另一种方案:在需要显示弹窗的地方,直接启动DialogActivity,然后原Activity正常退出(finish)。这样,弹窗由DialogActivity显示,原Activity已经销毁。 总结:我们可以在退出Activity时启动一个透明的Activity来显示弹窗,这样就能解决在Activity销毁过程中无法显示弹窗的问题。 注意:如果弹窗需要与用户交互,并且交互结果需要影响原Activity的数据,那么需要考虑使用startActivityForResult或者通过ViewModel共享数据(但原Activity已经销毁,所以不能共享,可以考虑使用单例或数据库存储)。 另外,引用[4]提到去除“Android正在启动”弹窗,虽然与我们问题无关,但提醒我们系统弹窗的处理可能需要特殊方式。 因此,根据需求,如果弹窗是原Activity退出时必须要显示的,那么使用透明Activity的方式是可行的。 相关问题: 1. 如何在Android中实现全局弹窗? 2. 如何拦截Android的返回键事件? 3. 如何避免在Activity销毁时显示弹窗导致的异常? 4. 如何设计一个弹窗管理类来统一处理应用中的弹窗? 根据用户的问题,我们给出了使用透明Activity的方案,并提供了代码示例。但请注意,实际开发中需要根据具体业务调整。</think>在 Android 开发中,当退出 Activity 时执行逻辑并显示弹窗,可通过以下方法实现: ### 方法 1:在 `onBackPressed()` 中处理(推荐) ```java @Override public void onBackPressed() { // 创建并显示弹窗 new AlertDialog.Builder(this) .setTitle("确认退出") .setMessage("确定要退出吗?") .setPositiveButton("确定", (dialog, which) -> { // 执行退出逻辑 super.onBackPressed(); // 继续执行退出操作 }) .setNegativeButton("取消", null) .show(); } ``` **说明**: - 覆盖 `onBackPressed()` 拦截返回键事件 - 显示弹窗确认后调用 `super.onBackPressed()` 执行默认退出 - 避免直接 `finish()` 导致窗口泄漏[^1] ### 方法 2:在 `finish()` 前触发 ```java public void customFinish() { // 显示弹窗 new AlertDialog.Builder(this) .setTitle("提示") .setMessage("正在保存数据...") .setCancelable(false) .show(); // 模拟异步操作 new Handler().postDelayed(() -> { // 完成操作后结束Activity finish(); }, 2000); } // 调用示例 buttonExit.setOnClickListener(v -> customFinish()); ``` ### 方法 3:使用透明 Activity 实现弹窗(复杂场景) 1. 创建透明主题: ```xml <!-- styles.xml --> <style name="Theme.Transparent" parent="Theme.AppCompat.Dialog"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> </style> ``` 2. 在 Manifest 注册: ```xml <activity android:name=".DialogActivity" android:theme="@style/Theme.Transparent" android:excludeFromRecents="true"/> ``` 3. 在退出时启动透明 Activity: ```java @Override public void onBackPressed() { Intent intent = new Intent(this, DialogActivity.class); startActivity(intent); finish(); // 结束当前Activity } ``` 4. 在 `DialogActivity` 中显示弹窗: ```java public class DialogActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new AlertDialog.Builder(this) .setMessage("退出后的提示") .setOnDismissListener(dialog -> finish()) // 关闭弹窗后结束Activity .show(); } } ``` ### 注意事项 1. **生命周期冲突**: - 避免在 `onDestroy()` 中显示弹窗(窗口 token 已失效) - 推荐在 `onBackPressed()` 或自定义退出方法中处理[^1] 2. **内存泄漏预防**: ```java @Override protected void onDestroy() { if (dialog != null && dialog.isShowing()) { dialog.dismiss(); // 确保销毁前关闭弹窗 } super.onDestroy(); } ``` 3. **异步操作处理**: - 如需网络请求等异步操作,使用 `ViewModel` + `LiveData` 管理状态 - 在弹窗关闭后调用 `finish()` 4. **回退栈管理**: - 多 Activity 场景需注意回退栈行为[^2] - 使用 `Intent.FLAG_ACTIVITY_CLEAR_TOP` 清理栈顶 Activity ### 备选方案 - **使用 DialogFragment**: ```java public class ExitDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) .setTitle("确认退出") .setPositiveButton("确定", (d, w) -> requireActivity().finish()) .create(); } } // 调用方式 new ExitDialog().show(getSupportFragmentManager(), "exit_dialog"); ``` [^1]: 在 Activity 生命周期中需注意弹窗的显示/销毁时机,避免因 Activity 已销毁导致 `WindowLeaked` 异常。 [^2]: Android 回退栈管理机制决定了 Activity 的销毁顺序,多 Activity 场景需特别注意栈内关系。 [^3]: 透明 Activity 方案可解决复杂弹窗需求,但增加了架构复杂度。 [^4]: 系统级弹窗(如启动弹窗)需修改框架代码,普通应用无需考虑。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值