工作需求,需要加载一个在线pdf,链接以“.pdf"结尾。通过查找,大都需要先把pdf文件下载下来,然后再加载,有以下几种实现方式:
方法一 :参考谷歌demo(android-PdfRendererBasic)
这个方案的好处是对apk安装包的体积基本无影响;
缺点 ①遇到PDF文件过大的时候可能OOM ②只能查看PDF文件,无法拓展,如果后续出现Word文档则无法满足。
方法二:使用JS 处理支持webview阅读pdf
将https://github.com/mozilla/pdf.js/下下来放到项目的assets下面,然后将这些copy到data下或者sd卡中,pdf也下载到相对目录下,然后就可以同上一样作为本地服务器一样阅读pdf了
缺点:
- 包增大几兆。
- 展示出来的样式太复杂,类似pdf工具的界面,太丑了。
- 无法展示水印
方法三:使用第三方SDK(比如:PdfViewPager、AndroidPdfViewer、android-pdfview)
AndroidPdfViewer:
优点:完美展示
缺点:使用后apk包增大15兆(真心没法接受)
android-pdfview:
优点:正常展示
缺点:
- 包大小增加三、四兆(勉强可以接受)。
- 水印无法展示出来(硬伤啊)
方法四:使用腾讯浏览服务
优点:
- 完美展示,水印也可以展示出来
- 包大小增加只有几十K
经过多次尝试,选择了方法四的解决方案:
代码如下
/**
* 使用x5内核加载pdf
*/
private void loadPdf() {
tbsReaderView = new TbsReaderView(this, this);
LinearLayout rootRl = (LinearLayout) findViewById(R.id.root);
rootRl.addView(tbsReaderView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
new LoadPDFAsyncTask(pdfName, new LoadPDFAsyncTask.OnLoadPDFListener() {
@Override
public void onCompleteListener(File file) {
Bundle bundle = new Bundle();
bundle.putString("filePath", file.getPath());
bundle.putString("tempPath", Environment.getExternalStorageDirectory().getPath());
boolean result = tbsReaderView.preOpen("pdf", false);
if (result) {
tbsReaderView.openFile(bundle);
mLoadingDialog.dismiss();
}
}
@Override
public void onFailureListener() {
ToastUtil.showToast(mContext, "加载失败");
mLoadingDialog.dismiss();
}
@Override
public void onProgressListener(Integer curPro, Integer maxPro) {
}
}).execute(webUrl);
}
下载工具类
public class LoadPDFAsyncTask extends AsyncTask<String, Integer, File> {
private OnLoadPDFListener onLoadPDFListener;
private String filePath = Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "zxp" + File.separator + "pdf";
private String fileName;
public LoadPDFAsyncTask(String fileName) {
this.fileName = fileName;
}
public LoadPDFAsyncTask(String fileName, OnLoadPDFListener onLoadPDFListener){
this.fileName = fileName;
this.onLoadPDFListener = onLoadPDFListener;
}
public void setOnLoadPDFListener(OnLoadPDFListener onLoadPDFListener) {
this.onLoadPDFListener = onLoadPDFListener;
}
//这里是开始线程之前执行的,是在UI线程
@Override
protected void onPreExecute() {
super.onPreExecute();
}
//当任务被取消时回调
@Override
protected void onCancelled() {
super.onCancelled();
if (onLoadPDFListener != null) onLoadPDFListener.onFailureListener();
}
//当任务被取消时回调
@Override
protected void onCancelled(File file) {
super.onCancelled(file);
}
//子线程中执行
@Override
protected File doInBackground(String... strings) {
String httpUrl = strings[0];
if (TextUtils.isEmpty(httpUrl)) {
if (onLoadPDFListener != null) onLoadPDFListener.onFailureListener();
}
File pathFile = new File(filePath);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
File pdfFile = new File(filePath + File.separator + fileName);
if (pdfFile.exists()) {
return pdfFile;
}
try {
URL url = new URL(httpUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.connect();
int count = conn.getContentLength(); //文件总大小 字节
int curCount = 0; // 累计下载大小 字节
int curRead = -1;// 每次读取大小 字节
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream is = conn.getInputStream();
FileOutputStream fos = new FileOutputStream(pdfFile);
byte[] buf = new byte[1024];
while ((curRead = is.read(buf)) != -1) {
curCount += curRead;
fos.write(buf, 0, curRead);
publishProgress(curCount, count);
}
fos.close();
is.close();
conn.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
if (onLoadPDFListener != null) onLoadPDFListener.onFailureListener();
return null;
}
return pdfFile;
}
//更新进度
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (onLoadPDFListener != null) {
onLoadPDFListener.onProgressListener(values[0], values[1]);
}
}
//当任务执行完成是调用,在UI线程
@Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
if (onLoadPDFListener != null) {
if (file != null && file.exists()) {
onLoadPDFListener.onCompleteListener(file);
} else {
onLoadPDFListener.onFailureListener();
}
}
}
//下载PDF文件时的回调接口
public interface OnLoadPDFListener {
//下载完成
void onCompleteListener(File file);
//下载失败
void onFailureListener();
//下载进度 字节
void onProgressListener(Integer curPro, Integer maxPro);
}
需要注意的地方:
使用腾讯浏览服务,需要载加载界面退出的时候调用一个方法,否则下次加载时会一直提示”加载中“
@Override
protected void onDestroy() {
super.onDestroy();
if (tbsReaderView != null) {
tbsReaderView.onStop();
}
}