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

Android PDF下载应用断网无法续传且打开空白页问题求助

问题修复方案

根因说明

  • 空白PDF问题:pdfView的onCreate方法中,无论文件是否下载完成,都会直接执行showPdf()加载本地文件,未下载完成的空文件/不完整文件就会显示空白页。
  • 无法断点续传问题:现有下载逻辑每次都会从头请求完整文件,用覆盖模式写入本地,没有读取本地已下载的字节长度、也没有给HTTP请求加断点续传所需的Range头,断网重启后无法接续之前的下载进度。
  • 额外逻辑问题:原有代码在子线程的doInBackground中手动调用onPostExecute操作UI,会存在线程安全异常风险。

代码修改步骤

1. 修复提前加载PDF的问题

修改pdfView.java的onCreate方法,删除全局的showPdf()调用,仅当本地文件已完整存在时才直接加载:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pdf_view);
    pdfView = (PDFView) findViewById(R.id.pdfView); // 提前初始化避免空指针

    Intent intent = getIntent();
    URL = intent.getStringExtra("File URL");
    fileName = intent.getStringExtra("File Name");

    File intDirectory = getFilesDir();
    File folder = new File(intDirectory, "pdf");
    boolean isDirectoryCreated = folder.exists();
    if (!isDirectoryCreated) {
        isDirectoryCreated= folder.mkdir();
    }
    if(isDirectoryCreated) {
        directory = new File(folder, fileName);
        try {
            directory.createNewFile();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        if (directory.length() == 0) {
            AsyncParameters param = new AsyncParameters(URL, directory);
            DownloadAsync Downloader = new DownloadAsync();
            Downloader.execute(param);
        } else {
            // 只有本地文件非空的时候才直接加载
            showPdf();
        }
        // 删除原来此处的全局showPdf调用
    }
}

2. 新增断点续传逻辑

修改DownloadAsync类的执行逻辑,支持断点续传、规范生命周期调用:

@Override
protected Void doInBackground(AsyncParameters... params) {
    String fileURL = params[0].URL;
    File directory = params[0].directory;
    long downloadedLength = directory.length(); // 读取本地已下载的字节数
    HttpURLConnection c = null;
    InputStream in = null;
    RandomAccessFile outputFile = null; // 支持随机写入,适配断点续传

    try {
        URL u = new URL(fileURL);
        c = (HttpURLConnection) u.openConnection();
        // 设置断点续传请求头,从已下载的位置开始请求剩余内容
        c.setRequestProperty("Range", "bytes=" + downloadedLength + "-");
        c.connect();

        int responseCode = c.getResponseCode();
        // 206是断点续传正常响应码,200代表服务器不支持续传返回全量文件
        if (responseCode != 200 && responseCode != 206) {
            throw new Exception("下载请求失败,响应码:" + responseCode);
        }

        in = c.getInputStream();
        outputFile = new RandomAccessFile(directory, "rw");
        // 移动文件指针到已下载的末尾位置,追加写入
        outputFile.seek(downloadedLength);

        byte[] buffer = new byte[8192];
        int len1 = 0;
        while ((len1 = in.read(buffer)) > 0) {
            outputFile.write(buffer, 0, len1);
        }
    } catch (Exception e) {
        e.printStackTrace();
        // 切换到主线程更新弹窗提示
        runOnUiThread(() -> pDialog.setMessage("下载出错,请检查网络后重试"));
    } finally {
        // 资源释放
        try {
            if (outputFile != null) outputFile.close();
            if (in != null) in.close();
            if (c != null) c.disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

// 重写AsyncTask原生onPostExecute,自动在主线程执行
@Override
protected void onPostExecute(Void aVoid) {
    super.onPostExecute(aVoid);
    if (pDialog != null && pDialog.isShowing()) {
        pDialog.dismiss();
    }
    showPdf();
}

3. 可选优化

可以在首次下载成功后,将对应PDF的完整文件大小存储到SharedPreferences中,每次打开时对比本地文件大小和存储的完整大小,不一致就继续续传,避免服务器不支持断点续传时加载不完整文件的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:24:05