You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AsyncTask执行完毕后返回值且不阻塞UI线程?

解决AsyncTask结合OkHttp上传文件的非阻塞回调问题

我完全懂你的需求——不想用get()把AsyncTask变成同步阻塞UI线程,而是通过接口委托来灵活处理上传过程中的状态和结果,这才是Android异步操作的正确打开方式,能有效避免ANR,还能让UI逻辑和网络操作解耦。

先给你完善后的完整代码实现:

// 首先定义回调接口,用来传递上传进度和结果
public interface TaskInterface<T, P> {
    // 上传成功时回调结果
    void onTaskSuccess(T result);
    // 上传失败时回调错误信息
    void onTaskFailed(String errorMsg);
    // 上传进度更新时回调
    void onProgressUpdate(P progress);
}

// 完善后的UploadFile AsyncTask
static class UploadFile extends AsyncTask<Void, Float, String> {
    private TaskInterface<String, Float> delegate;
    private String url;
    private File file;
    private MediaType fileType;

    // 构造函数,传入必要参数和回调委托
    public UploadFile(String url, File file, MediaType fileType, TaskInterface<String, Float> delegate) {
        this.url = url;
        this.file = file;
        this.fileType = fileType;
        this.delegate = delegate;
    }

    @Override
    protected String doInBackground(Void... voids) {
        try {
            // 自定义RequestBody来监听上传进度
            RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file", file.getName(),
                            new RequestBody() {
                                @Override
                                public MediaType contentType() {
                                    return fileType;
                                }

                                @Override
                                public long contentLength() throws IOException {
                                    return file.length();
                                }

                                @Override
                                public void writeTo(BufferedSink sink) throws IOException {
                                    long fileLength = file.length();
                                    byte[] buffer = new byte[4096];
                                    FileInputStream in = new FileInputStream(file);
                                    long uploaded = 0;

                                    try {
                                        int read;
                                        while ((read = in.read(buffer)) != -1) {
                                            // 计算进度并发布
                                            uploaded += read;
                                            float progress = (float) uploaded / fileLength;
                                            publishProgress(progress);

                                            sink.write(buffer, 0, read);
                                            sink.flush();
                                        }
                                    } finally {
                                        in.close();
                                    }
                                }
                            })
                    .build();

            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();

            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();

            if (response.isSuccessful() && response.body() != null) {
                return response.body().string();
            } else {
                return "上传失败:" + response.code();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "上传异常:" + e.getMessage();
        }
    }

    @Override
    protected void onProgressUpdate(Float... values) {
        super.onProgressUpdate(values);
        // 把进度回调给UI线程
        if (delegate != null) {
            delegate.onProgressUpdate(values[0]);
        }
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        // 根据结果触发成功或失败回调
        if (delegate != null) {
            if (result.startsWith("上传失败") || result.startsWith("上传异常")) {
                delegate.onTaskFailed(result);
            } else {
                delegate.onTaskSuccess(result);
            }
        }
    }
}

下面是在UI线程中的调用示例(比如Activity里):

File uploadFile = new File("/sdcard/test.jpg");
MediaType imageType = MediaType.parse("image/jpeg");

new UploadFile("https://your-upload-url.com", uploadFile, imageType, new TaskInterface<String, Float>() {
    @Override
    public void onTaskSuccess(String result) {
        // UI线程处理成功结果,比如更新TextView
        runOnUiThread(() -> {
            tvResult.setText("上传成功:" + result);
        });
    }

    @Override
    public void onTaskFailed(String errorMsg) {
        // UI线程处理失败情况
        runOnUiThread(() -> {
            tvResult.setText("上传失败:" + errorMsg);
        });
    }

    @Override
    public void onProgressUpdate(Float progress) {
        // 更新进度条,比如设置进度值
        runOnUiThread(() -> {
            progressBar.setProgress((int) (progress * 100));
        });
    }
}).execute();

最后给你划几个关键要点:

  • 回调接口解耦:TaskInterface把上传的状态(进度、成功、失败)传递给调用方,AsyncTask只负责网络操作,不用关心UI怎么处理
  • 彻底避免UI阻塞:全程没有使用get()方法,所有UI更新都通过AsyncTask的生命周期方法或runOnUiThread回到主线程,保证线程安全
  • OkHttp进度监听:通过自定义RequestBody的writeTo方法,实时计算上传进度并通过publishProgress通知主线程
  • 清晰的参数传递:通过构造函数传入上传所需的URL、文件、媒体类型和回调委托,代码逻辑更直观

内容的提问来源于stack exchange,提问作者ryuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:42:38