AsyncTask类中使用startActivityForResult与onActivityResult的问题解决
问题分析与解决方案
这个问题我之前也碰到过,核心原因是你把图片选择的结果处理逻辑放到了AsyncTask子类里——onActivityResult是Activity(或Fragment)专属的生命周期方法,AsyncTask作为后台任务类,既没有这个方法的上下文,调用super.onActivityResult也完全没有意义(因为AsyncTask的父类根本没有这个方法)。
下面是两种可行的解决办法,优先推荐第一种,更符合Android的职责分离设计:
方案一:将图片选择逻辑移到宿主Activity中(推荐)
把启动相册、处理选择结果的逻辑全部放到你的Activity里,FTPSubir只专注于FTP上传的后台任务,这样分工更清晰,也避免了生命周期冲突。
步骤1:修改宿主Activity代码
在你的Activity中实现相册启动和结果处理:
public class YourActivity extends AppCompatActivity { private static final int SELECT_FILE = 1; // 替换成你的FTP服务器地址 private String ftpServerIp = "xxx.xxx.xxx.xxx"; // 启动相册的方法,你可以在按钮点击等事件中调用它 public void abrirGaleria() { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult( Intent.createChooser(intent, "Seleccione una imagen"), SELECT_FILE ); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { super.onActivityResult(requestCode, resultCode, imageReturnedIntent); if (requestCode == SELECT_FILE && resultCode == RESULT_OK) { Uri selectedImage = imageReturnedIntent.getData(); String selectedPath = selectedImage.getPath(); if (selectedPath != null) { File rutaCompleta = new File(selectedPath); // 拿到图片路径后,启动FTP上传任务 FTPSubir ftpUploadTask = new FTPSubir(ftpServerIp, this, rutaCompleta); ftpUploadTask.execute(); } } } }
步骤2:重构FTPSubir类
去掉原来的abrirGaleria和onActivityResult方法,添加接收图片文件的构造方法,让它只负责后台上传:
public class FTPSubir extends AsyncTask<Void, Integer, Long> { private static final String USUARIO = "你的FTP用户名"; private static final String PASS = "你的FTP密码"; private String ip; private String usuario; private String contrasena; private FTPClient ftpClient; private BufferedInputStream bufferIn; private File rutaCompleta; private Context context; // 新增构造方法,直接接收选中的图片文件 public FTPSubir(String ip, Context context, File rutaCompleta) { this.ip = ip; this.usuario = USUARIO; this.contrasena = PASS; this.context = context; this.rutaCompleta = rutaCompleta; } // 保留原有的登录逻辑 public boolean login() throws IOException { System.out.println("Conectando . . ."); try { ftpClient = new FTPClient(); ftpClient.connect(ip); } catch (Exception e) { e.printStackTrace(); System.out.println("Imposible conectar . . ."); return false; } ftpClient.enterLocalPassiveMode(); if (ftpClient.login(usuario, contrasena)) { System.out.println("Login correcto . . ."); return true; } else { System.out.println("Login incorrecto . . ."); return false; } } // 保留原有的文件上传逻辑 public boolean SubirArchivo() throws IOException { ftpClient.enterLocalActiveMode(); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); if (ftpClient.changeWorkingDirectory("ftp")) { System.out.println("Carpeta ftp cambiada . . ."); bufferIn = new BufferedInputStream(new FileInputStream(rutaCompleta)); if (ftpClient.storeFile(rutaCompleta.getName(), bufferIn)) { System.out.println("Archivo subido . . ."); bufferIn.close(); return true; } else { System.out.println("Imposible subir archivo . . ."); bufferIn.close(); return false; } } else { System.out.println("Carpeta ftp imposible cambiar . . ."); return false; } } // 后台执行上传任务 @Override protected Long doInBackground(Void... voids) { try { if (login()) { SubirArchivo(); } } catch (IOException e) { e.printStackTrace(); } return null; } // 上传完成后的UI反馈(可选) @Override protected void onPostExecute(Long aLong) { super.onPostExecute(aLong); Toast.makeText(context, "上传完成", Toast.LENGTH_SHORT).show(); } // 保留原有的getter/setter方法(如果需要的话) public String getUsuario() { return usuario; } public void setUsuario(String usuario) { this.usuario = usuario; } public String getContrasena() { return contrasena; } public void setContrasena(String contrasena) { this.contrasena = contrasena; } }
方案二:通过接口回调传递结果(不推荐)
如果一定要在FTPSubir中处理结果,可以定义一个回调接口,让Activity实现接口,在onActivityResult中把结果传递给FTPSubir。但这种方式会让代码耦合度变高,不如方案一清晰。
步骤1:定义回调接口
public interface OnImageSelectedListener { void onImageSelected(File imageFile); }
步骤2:修改FTPSubir类
实现接口,并在回调中拿到图片文件:
public class FTPSubir extends AsyncTask<Void, Integer, Long> implements OnImageSelectedListener { // ... 保留原有成员变量 ... private OnImageSelectedListener listener; public FTPSubir(String ip, Context context) { this.ip = ip; this.context = context; this.listener = this; // ... 其他初始化代码 ... } // 实现回调方法 @Override public void onImageSelected(File imageFile) { this.rutaCompleta = imageFile; // 启动上传任务 this.execute(); } // ... 保留原有login、SubirArchivo等方法 ... }
步骤3:修改Activity代码
实现接口,在onActivityResult中调用回调:
public class YourActivity extends AppCompatActivity implements OnImageSelectedListener { private FTPSubir ftpSubir; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ftpSubir = new FTPSubir("你的FTP地址", this); } public void abrirGaleria() { // 同方案一的相册启动代码 } @Override protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { super.onActivityResult(requestCode, resultCode, imageReturnedIntent); if (requestCode == SELECT_FILE && resultCode == RESULT_OK) { Uri selectedImage = imageReturnedIntent.getData(); String selectedPath = selectedImage.getPath(); if (selectedPath != null) { File rutaCompleta = new File(selectedPath); // 调用回调传递结果 ftpSubir.onImageSelected(rutaCompleta); } } } @Override public void onImageSelected(File imageFile) { // 这里可以留空,因为FTPSubir自己实现了这个方法 } }
内容的提问来源于stack exchange,提问作者Richard Álvarez
相关产品推荐
相关产品推荐

