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

使用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();
        }
        // 这里处理最终的读取结果
    }
}

关键注意点:

  1. 放弃用readLine()做进度计算:除非你能确保文本每行大小固定、且能通过行数估算进度,否则字节流是更可靠的选择。
  2. 确认服务器返回Content-Length:如果是网络请求,要保证HTTP响应头里包含这个字段,否则totalSize会是-1,进度计算就会失效。这种情况下可以改用不确定进度的对话框(setIndeterminate(true))。
  3. 异常处理要周全:流的读取和关闭必须放在try-finally块里,避免因为异常导致线程卡死。
  4. 绝对不要在doInBackground操作UI:所有UI更新必须通过onProgressUpdate或onPostExecute,这是AsyncTask的基础规则。

如果你的场景确实只需要读取文本、不需要实时进度,那可以读完所有行再处理,但这样就没法更新进度条了——按需选择就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:17:06