Android拆分ImagePicker为独立类后调用startActivityForResult崩溃
崩溃原因
你的代码有3个核心错误,直接导致调用startActivityForResult()时崩溃:
ImagePicker类继承了Activity,但你通过new ImagePicker()手动创建实例。Activity是Android系统托管的组件,必须通过Manifest注册、由系统完成实例化和生命周期初始化,手动new出的Activity对象没有关联的上下文和窗口令牌,调用启动Activity的API会直接抛出异常。- 你在新起的子线程中调用
chooseImage()执行UI操作和启动Activity,Android规定所有UI操作、组件启动逻辑必须在主线程执行,子线程直接调用会触发线程检查异常。 - 你把View控件声明为
public static,这种写法会持有Activity引用造成内存泄漏,同时静态变量的生命周期和Activity不同步,也容易触发空指针。
修复后可运行代码
1. 重写ImagePicker类,不要继承Activity
把它改成普通工具类,持有宿主Activity的引用完成相关操作:
package com.shubhamr69.app.Components; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.view.View; import android.widget.Button; public class ImagePicker { private static final int REQUEST_CODE_PICK_IMAGE = 200; private final Activity hostActivity; private Button triggerButton; private Uri selectedImageUri = null; private String selectedImagePath = ""; private Runnable onImagePickedCallback = () -> {}; // 构造时传入绑定的宿主Activity public ImagePicker(Activity activity) { this.hostActivity = activity; } // 绑定触发选择的按钮 public void initialize(Button button) { triggerButton = button; triggerButton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { // 直接在主线程调用选择逻辑,不要开子线程 openImageChooser(); } }); } private void openImageChooser() { Intent pickIntent = new Intent(Intent.ACTION_PICK); pickIntent.setType("image/*"); // 通过宿主Activity启动选择器 hostActivity.startActivityForResult(pickIntent, REQUEST_CODE_PICK_IMAGE); } // 提供方法给宿主Activity转发onActivityResult结果 public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode != REQUEST_CODE_PICK_IMAGE) return; if (resultCode == Activity.RESULT_OK && data != null) { selectedImageUri = data.getData(); selectedImagePath = selectedImageUri != null ? selectedImageUri.getPath() : ""; // 切主线程执行选中回调 hostActivity.runOnUiThread(onImagePickedCallback); } } public void setOnImagePicked(Runnable callback) { this.onImagePickedCallback = callback; } public Uri getContentUri() { return selectedImageUri; } public String getImagePath() { return selectedImagePath; } }
2. 修改MainActivity代码
移除静态View变量,增加结果转发逻辑:
package com.shubhamr69.app; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.shubhamr69.app.Components.ImagePicker; public class MainActivity extends Activity { private ImagePicker imagePicker; private ImageView imageDisplay; private TextView statusLabel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupViews(); } private void setupViews() { // 传入当前Activity实例初始化选择器 imagePicker = new ImagePicker(this); statusLabel = findViewById(R.id.Label1); imageDisplay = findViewById(R.id.Image1); Button pickButton = findViewById(R.id.ImagePicker1); imagePicker.initialize(pickButton); statusLabel.setText("初始化完成,点击按钮选择图片"); imagePicker.setOnImagePicked(new Runnable(){ @Override public void run() { imageDisplay.setImageURI(imagePicker.getContentUri()); statusLabel.setText("图片选择完成"); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // 把选择结果转发给ImagePicker处理 imagePicker.onActivityResult(requestCode, resultCode, data); statusLabel.setText("收到选择结果"); } }
额外注意
- 所有Activity、Service、BroadcastReceiver等系统组件都不要手动通过new创建实例,必须在Manifest注册后由系统实例化。
- 操作UI、启动Activity/Service等操作必须在主线程执行,不要随意开子线程调用这类API。
- 不要把View、Activity等Context相关的对象声明为static静态变量,会造成严重的内存泄漏。
内容的提问来源于stack exchange,提问作者SHUBHAMR69
相关产品推荐
相关产品推荐

