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

