Android 實現PDF檔案的檢視(本地和網路檔案)
PDF檔案大家應該不陌生,說的簡單點,其實我認為就是一個全圖片的Word,裡面的每個頁面都可以看做是一張帶文字的圖片,接下來我們看看在Android應用裡如何讀取和檢視PDF檔案內容。
1 在專案的gradle中增加如下程式碼:
compile 'com.joanzapata.pdfview:android-pdfview:[email protected]'
先看看佈局檔案程式碼
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include layout="@layout/title_all" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.joanzapata.pdfview.PDFView android:id="@+id/pdf" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:id="@+id/tv_page" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textColor="@color/colorAccent" android:layout_alignParentTop="true" android:textSize="18sp" /> </RelativeLayout> </LinearLayout>
其中PDFView控制元件就是pdfview庫裡面的檢視PDF的控制元件,接下來宣告並初始化後檢視本地Asserts資源下的PDF檔案,程式碼如下
pdf.fromAsset("abcd.pdf") .defaultPage(1) .showMinimap(false) .enableSwipe(true) .onPageChange(this) .load();
這樣就可以檢視pdf檔案內容了,但是如果是網上線上檢視PDF檔案該如何實現呢?
我的思路是這樣:
第一步,把PDF檔案下載下來;
第二步,把檔案儲存在手機儲存中;
第三步,讀取手機SD卡的PDF檔案。
接下來就一步一步實現,當然下載、儲存、讀取SD卡的內容首先就得有許可權,相關許可權的申請就不多說了,基本功你懂得!
下載的話方式很多,你可以用任何可以下載檔案的網路框架,我用的是okhttp下載的,程式碼如下
/** * 下載 */ private void downloadFile() { OkHttpUtils.build().download(path, savePath, new OkHttpUtils.OnDownloadListener() { @Override public void onDownloadSuccess(File file) { tvPage.setText("載入完成正在開啟.."); showPdf(file.getPath()); } @Override public void onDownloading(int progress) { Log.i("JAVA", "onDownloading"+progress); tvPage.setText("正在載入("+progress+"/100)"); } @Override public void onDownloadFailed() { Log.i("JAVA", "onDownloadFailed"); tvPage.setText("載入失敗.."); } }); }
下載方法中path是網路上PDF檔案的額下載全路徑,savePath是下載下來的檔案儲存的目錄,onDownloadSuccess是下載完成後的回撥方法,回撥的是下載的檔案,file.getPath()可以獲取這個檔案儲存的路徑地址,okhttp我自己封裝了一個工具類,程式碼奉上
** * OkHttp3工具類 * 2018/9/11 */ public class OkHttpUtils { private static OkHttpClient client; private static OkHttpUtils okHttpUtils; private OkHttpCallback callback; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1://異常 IOException e = (IOException) msg.obj; LogUtils.i("ruin", "e--> " + e.toString()); callback.onError(e); break; case 2://成功 String result = (String) msg.obj; callback.onResponse(result); break; } } }; /** * http請求 */ public static OkHttpUtils build() { OkHttpClient.Builder sBuilder = new OkHttpClient.Builder(); client = sBuilder.build(); okHttpUtils = new OkHttpUtils(); return okHttpUtils; } //設定回撥方法 public OkHttpUtils setCallback(OkHttpCallback callback) { this.callback = callback; return okHttpUtils; } //post請求 public OkHttpUtils postOkHttp(String url, Map<String, Object> params) { FormBody.Builder builder = new FormBody.Builder(); String temp = ""; for (String key : params.keySet()) { builder.add(key, String.valueOf(params.get(key))); temp += (key + "=" + String.valueOf(params.get(key)) + "&"); } LogUtils.i("LogUtils", "url =" + url + "?" + temp); FormBody formBody = builder.build(); Request request = new Request.Builder() .url(url) .post(formBody) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Message msg = Message.obtain(); msg.what = 1; msg.obj = e; handler.sendMessage(msg); } @Override public void onResponse(Call call, Response response) throws IOException { String result = response.body().string(); Message msg = Message.obtain(); msg.what = 2; msg.obj = result; handler.sendMessage(msg); } }); return okHttpUtils; } public OkHttpUtils postAsync(String url, Map<String, Object> params) { RequestBody requestBody; if (params == null) { params = new HashMap<>(); } /** * OKhttp3.0之後版本 */ FormBody.Builder builder = new FormBody.Builder(); /** * 在這對新增的引數進行遍歷,map遍歷有四種方式,如果想要了解的可以網上查詢 */ String temp = ""; for (Map.Entry<String, Object> map : params.entrySet()) { String key = map.getKey(); Object value; value = map.getValue() == null ? "" : map.getValue(); builder.add(key, String.valueOf(value)); temp += (key + "=" + String.valueOf(value)); } LogUtils.i("LogUtils", "url =" + url + "?" + temp); requestBody = builder.build(); final Request request = new Request.Builder().url(url).post(requestBody).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Message msg = Message.obtain(); msg.what = 1; msg.obj = e; handler.sendMessage(msg); } @Override public void onResponse(Call call, Response response) throws IOException { String result = response.body().string(); Message msg = Message.obtain(); msg.what = 2; msg.obj = result; handler.sendMessage(msg); } }); return okHttpUtils; } //請求回撥介面 public interface OkHttpCallback { void onError(Exception e); void onResponse(String result); } /** * 判斷是否有網路連線 */ private boolean isNetworkConnected(@NonNull Context context) { ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); return mNetworkInfo != null && mNetworkInfo.isAvailable(); } /** * @param url 下載連線 * @param saveDir 儲存下載檔案的SDCard目錄 * @param listener 下載監聽 */ public void download(final String url, final String saveDir, final OnDownloadListener listener) { Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 下載失敗 listener.onDownloadFailed(); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; // 儲存下載檔案的目錄 String savePath = isExistDir(saveDir); try { is = response.body().byteStream(); long total = response.body().contentLength(); File file = new File(savePath, getNameFromUrl(url)); fos = new FileOutputStream(file); long sum = 0; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); sum += len; int progress = (int) (sum * 1.0f / total * 100); // 下載中 listener.onDownloading(progress); } fos.flush(); // 下載完成 listener.onDownloadSuccess(file); } catch (Exception e) { listener.onDownloadFailed(); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { } try { if (fos != null) { fos.close(); } } catch (IOException e) { } } } }); } /** * 判斷下載目錄是否存在 */ private String isExistDir(String saveDir) throws IOException { // 下載位置 File downloadFile = new File(Environment.getExternalStorageDirectory(), saveDir); if (!downloadFile.mkdirs()) { downloadFile.createNewFile(); } String savePath = downloadFile.getAbsolutePath(); return savePath; } /** * 從下載連線中解析出檔名 */ @NonNull private String getNameFromUrl(String url) { return url.substring(url.lastIndexOf("/") + 1); } public interface OnDownloadListener { /** * 下載成功 */ void onDownloadSuccess(File file); /** * 下載進度 */ void onDownloading(int progress); /** * 下載失敗 */ void onDownloadFailed(); } }
當然要用okhttp下載需要新增okhttp庫檔案,我用的是okhttp3
compile 'com.squareup.okhttp3:okhttp:3.9.0'
在上面下載成功的回撥方法裡傳入下載的PDF檔案路徑開啟檔案 showPdf(file.getPath());
private void showPdf(String fileName) { if (TextUtils.isEmpty(fileName)) { Toast.makeText(this, "檔案不存在", Toast.LENGTH_SHORT).show(); } else { try { pdf.fromFile(new File(fileName)) .defaultPage(1) .showMinimap(false) .enableSwipe(true) .onLoad(new OnLoadCompleteListener() { @Override public void loadComplete(int nbPages) { float pageWidth = pdf.getOptimalPageWidth(); float viewWidth = pdf.getWidth(); pdf.zoomTo(viewWidth / pageWidth); pdf.loadPages(); } }) .onPageChange(this) .load(); } catch (FileNotFoundException e) { Toast.makeText(this, "檔案不存在", Toast.LENGTH_SHORT).show(); File file = new File(fileName); FileUtils.deleteFile(file); } } }
開啟之後就可以查看了,和檢視Asserts資源下的PDF檔案基本一樣了,有一個點差點忘了就是實現OnPageChangeListener介面,然後在重寫的onPageChanged方法中顯示當前檢視的頁面是多少頁和一共有多少頁
@Override public void onPageChanged(int page, int pageCount) { String pager = "頁碼(" + page + "/" + pageCount + ")"; tvPage.setText(pager); }
好了,pdf檔案檢視就這樣完成了,誰有更好的方法可以互相推薦學習。