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
相关产品推荐
相关产品推荐

