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

Android上传图片时用AsyncTask实现带百分比的水平进度条方案

实现带百分比的水平进度条上传

嗨,很高兴帮你解决这个问题!要在AsyncTask上传时显示百分比进度,我们需要做几个关键修改:调整AsyncTask的泛型参数来传递进度数据、改用水平样式的进度对话框、在上传过程中计算并发布进度,最后更新UI。

下面是具体的修改步骤和完整代码示例:

1. 调整AsyncTask的泛型参数

原来的AsyncTask<Void,Void,String>只能处理无进度的任务,我们需要把中间的泛型改成Integer来传递进度百分比,所以修改为AsyncTask<byte[], Integer, String>:

  • 第一个参数byte[]:传入要上传的图片字节数组
  • 第二个参数Integer:发布的进度百分比
  • 第三个参数String:上传完成后的返回结果

2. 替换进度对话框为水平样式

在onPreExecute中,把原来的普通ProgressDialog改成水平样式,设置最大进度为100:

@Override
protected void onPreExecute() {
    super.onPreExecute();
    progressDialog = new ProgressDialog(MainActivity.this);
    progressDialog.setTitle("Image is Uploading");
    progressDialog.setMessage("Please Wait");
    progressDialog.setIndeterminate(false); // 关闭不确定模式
    progressDialog.setMax(100); // 设置最大进度为100
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); // 水平进度条样式
    progressDialog.setCancelable(false);
    progressDialog.show();
}

3. 修改上传逻辑,计算并发布进度

原来的Base64上传方式很难跟踪进度,我们改为直接上传图片字节流,分块写入输出流,实时计算已上传字节数占总字节数的比例:

首先修改UploadImageToServer方法,直接传递图片字节数组给AsyncTask:

public void UploadImageToServer(){
    FixBitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    byteArray = byteArrayOutputStream.toByteArray();
    // 不再转Base64,直接传字节数组
    AsyncTaskUploadClass uploadTask = new AsyncTaskUploadClass();
    uploadTask.execute(byteArray);
}

然后重写AsyncTask的核心方法:

class AsyncTaskUploadClass extends AsyncTask<byte[], Integer, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // 上面的水平进度Dialog代码
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        progressDialog.dismiss();
        Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        // 更新进度条的百分比
        progressDialog.setProgress(values[0]);
    }

    @Override
    protected String doInBackground(byte[]... params) {
        byte[] imageBytes = params[0];
        String uploadResult = "";
        HttpURLConnection httpURLConnection = null;
        OutputStream outputStream = null;
        try {
            URL url = new URL(URL);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setReadTimeout(20000);
            httpURLConnection.setConnectTimeout(20000);
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setDoInput(true);
            httpURLConnection.setDoOutput(true);

            // 设置请求头,传递文件名和数据类型
            httpURLConnection.setRequestProperty("Content-Type", "application/octet-stream");
            httpURLConnection.setRequestProperty("Image-Name", GetImageNameFromEditText);

            outputStream = httpURLConnection.getOutputStream();

            int totalBytes = imageBytes.length;
            int bytesWritten = 0;
            int bufferSize = 1024; // 每次写入1KB数据
            byte[] buffer = new byte[bufferSize];

            for (int i = 0; i < totalBytes; i += bufferSize) {
                int length = Math.min(bufferSize, totalBytes - i);
                System.arraycopy(imageBytes, i, buffer, 0, length);
                outputStream.write(buffer, 0, length);
                bytesWritten += length;

                // 计算并发布进度
                int progress = (int) ((bytesWritten * 100.0) / totalBytes);
                publishProgress(progress);
            }

            outputStream.flush();

            // 获取服务器响应
            int responseCode = httpURLConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(httpURLConnection.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line);
                }
                uploadResult = stringBuilder.toString();
            } else {
                uploadResult = "Upload failed, response code: " + responseCode;
            }

        } catch (Exception e) {
            e.printStackTrace();
            uploadResult = "Error: " + e.getMessage();
        } finally {
            try {
                if (outputStream != null) outputStream.close();
                if (httpURLConnection != null) httpURLConnection.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return uploadResult;
    }
}

4. 服务器端适配(可选)

如果你原来的服务器是接收Base64字符串的,需要修改服务器端代码来读取二进制流。比如PHP示例:

<?php
$imageName = $_SERVER['HTTP_IMAGE_NAME'];
$imageData = file_get_contents('php://input');
$savePath = 'uploads/' . $imageName;
if (!file_exists('uploads')) {
    mkdir('uploads', 0777, true);
}
if (file_put_contents($savePath, $imageData)) {
    echo "Upload successful";
} else {
    echo "Upload failed";
}
?>

关键说明

  • 去掉Base64编码直接上传字节流,既节省带宽,又能精准跟踪上传进度
  • publishProgress会在后台线程触发主线程的onProgressUpdate,符合Android的线程安全规则
  • 分块写入的bufferSize可按需调整,1KB是均衡的选择,太大可能导致进度更新不及时,太小会增加IO开销

这样修改后,你就能看到实时显示上传百分比的水平进度条了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 21:57:31