使用BufferedReader时AsyncTask的publishProgress不更新问题求助
解决AsyncTask结合BufferedReader时进度更新卡顿、publishProgress不执行的问题
嘿,我刚看完你的问题,这种情况我之前也踩过坑——AsyncTask的doInBackground里用BufferedReader读数据,结果后台线程直接卡住,进度条完全没反应,日志只打了第一条,后面的全没影了。核心问题大概率出在**BufferedReader.readLine()的阻塞特性**,或者你用错了读取方式来计算下载进度。
为什么会出现这个问题?
首先,readLine()是按行读取文本的方法,它会一直阻塞直到读到换行符或者流彻底结束。如果你的数据源(比如网络请求的输入流)没发送换行符,或者流没有被正确关闭,这个方法就会一直卡着不动,导致while循环里的后续代码(日志、publishProgress)根本执行不到。而且如果是下载二进制文件(比如APK、图片),用readLine完全是错误姿势——它会破坏二进制数据,还没法计算实时进度。
另外,就算是读取文本,要是没处理好流的结束条件,也会导致线程阻塞,整个AsyncTask直接停在那里“罢工”。
解决方案:换用字节流读取,实时计算进度
不管你是下载文件还是读取文本,想要实时更新进度,都应该用字节流来读取,这样能准确计算已读取的字节数,避免阻塞。下面给你改个实用的示例代码:
private class GetData extends AsyncTask<String, Integer, String> { private ProgressDialog progressDialog; @Override protected void onPreExecute() { super.onPreExecute(); progressDialog = new ProgressDialog(YourActivity.this); progressDialog.setMessage("加载中..."); progressDialog.setIndeterminate(false); progressDialog.setMax(100); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.show(); } @Override protected String doInBackground(String... params) { String urlStr = params[0]; InputStream inputStream = null; ByteArrayOutputStream outputStream = null; try { URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.connect(); // 获取总数据大小(网络请求需确保服务器返回Content-Length响应头) int totalSize = conn.getContentLength(); inputStream = conn.getInputStream(); outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; // 1KB缓冲,可根据需求调整 int bytesRead; int downloadedSize = 0; Log.d("AsyncTask", "开始读取数据"); // 第一个日志正常打印 while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); downloadedSize += bytesRead; // 计算当前进度百分比 int progress = totalSize > 0 ? (int) ((downloadedSize * 100) / totalSize) : 0; Log.d("AsyncTask", "当前进度:" + progress + "%"); // 现在这个日志能正常输出了 publishProgress(progress); } Log.d("AsyncTask", "数据读取完成"); // 这个日志也能正常打印了 return outputStream.toString("UTF-8"); // 返回读取到的文本内容 } catch (Exception e) { e.printStackTrace(); return "读取失败:" + e.getMessage(); } finally { // 确保流被正确关闭,避免资源泄漏 try { if (inputStream != null) inputStream.close(); if (outputStream != null) outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); progressDialog.setProgress(values[0]); } @Override protected void onPostExecute(String result) { super.onPostExecute(result); if (progressDialog.isShowing()) { progressDialog.dismiss(); } // 这里处理最终的读取结果 } }
关键注意点:
- 放弃用
readLine()做进度计算:除非你能确保文本每行大小固定、且能通过行数估算进度,否则字节流是更可靠的选择。 - 确认服务器返回
Content-Length:如果是网络请求,要保证HTTP响应头里包含这个字段,否则totalSize会是-1,进度计算就会失效。这种情况下可以改用不确定进度的对话框(setIndeterminate(true))。 - 异常处理要周全:流的读取和关闭必须放在
try-finally块里,避免因为异常导致线程卡死。 - 绝对不要在
doInBackground操作UI:所有UI更新必须通过onProgressUpdate或onPostExecute,这是AsyncTask的基础规则。
如果你的场景确实只需要读取文本、不需要实时进度,那可以读完所有行再处理,但这样就没法更新进度条了——按需选择就行。
内容的提问来源于stack exchange,提问作者Chayan Mistry
相关产品推荐
相关产品推荐

