Android应用内在线查看PDF文件

https://blog.csdn.net/choose_xt/article/details/78653370

下面介绍几种可行性较高的方案

一.PDFView

这个比较早,有几年没更新了,但可以满足一般的需求,手势放大缩小,左右滑动,体积也较小,对于Android版本可以兼容到较低版本,缺点也比较明显,不能查看带有水印和超链接的PDF

1.添加依赖 compile 'com.joanzapata.pdfview:android-pdfview:1.0.4@aar'

2.适用场景:加载本地asserts中的资源;加载内存中的文件(其实在线预览也就是先下载,然后查看)

3.show code

<?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">

    <TextView
        android:id="@+id/tv_page"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/colorAccent"
        android:textSize="18sp" />

    <com.joanzapata.pdfview.PDFView
        android:id="@+id/pdf"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

public class PdfReadActivity extends AppCompatActivity implements OnPageChangeListener {
    public static final String APP_NAME = "my/pdf";
    public static final String IS_LOAD_COMPLETE = "is_load_complete";
    public static final int LOAD_CANCEL = 0;
    public static final int LOAD_ERROR = 1;

    private MyHandler myHandler;
    private PDFView pdf;
    private TextView tvPage;
    private AsyncTask<String, Integer, String> task;
    private String pdfName;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pdf_read);
        pdf = (PDFView) findViewById(R.id.pdf);
        tvPage = (TextView) findViewById(R.id.tv_page);

        //Asserts资源查看
//        pdf.fromAsset("sample.pdf")
//                .defaultPage(1)
//                .showMinimap(false)
//                .enableSwipe(true)
//                .onPageChange(this)
//                .load();
//
        String path = getIntent().getStringExtra("path");

        myHandler = new MyHandler(this);

        if (TextUtils.isEmpty(path)) {
            Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
            finish();
        }
        startOpenPdf(path);
    }

    private void startOpenPdf(String path) {
        getPdfName(path);
        boolean isLoadComplete = SharedPreferencesUtils.getBooleanParam(this, IS_LOAD_COMPLETE, false);
        String pdfPath = checkApkExist();
        //若存在pdf文件...不存在则直接下载
        if (!TextUtils.isEmpty(pdfPath)) {
            if (isLoadComplete) {
                showPdf(pdfPath);
            } else {
                File file = new File(FileUtils.getRootFilePath() + APP_NAME, pdfName);
                FileUtils.deleteFile(file);
                task = new DownPdfFileTask().execute(path);
            }
        } else {
            task = new DownPdfFileTask().execute(path);
        }
    }

    private void getPdfName(String path) {
        try {
            URL url = new URL(path);
            String urlPath = url.getPath();
            pdfName = urlPath.substring(urlPath.lastIndexOf("/") + 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String checkApkExist() {
        String path = FileUtils.getRootFilePath() + APP_NAME;
        File file = new File(path, pdfName);
        return file.exists() ? path + "/" + pdfName : "";
    }

    private class DownPdfFileTask extends AsyncTask<String, Integer, String> {
        private File pdfFile;

        String result = null;

        @Override
        protected String doInBackground(String... params) {
            InputStream input = null;
            FileOutputStream fos = null;
            try {
                URL url = new URL(params[0]);
                String urlPath = url.getPath();
                pdfName = urlPath.substring(urlPath.lastIndexOf("/") + 1);
                url = new URL("http://resourcetest.com/" + URLEncoder.encode(pdfName));

                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(10000);
                connection.setRequestMethod("GET");
                if (HttpURLConnection.HTTP_OK != connection.getResponseCode()) {
                    return null;
                }
                String pdkDir = FileUtils.getRootFilePath() + APP_NAME;
                FileUtils.createDirectory(pdkDir);
                pdfFile = new File(pdkDir, pdfName);
                input = new BufferedInputStream(connection.getInputStream());
                fos = new FileOutputStream(pdfFile);

                int count;
                byte buf[] = new byte[1024];
                while ((count = input.read(buf)) != -1) {
                    if (isCancelled()) {
                        break;
                    }
                    fos.write(buf, 0, count);
                }
                result = pdkDir + "/" + pdfName;
            } catch (IOException e) {
                e.printStackTrace();
                if (pdfFile != null && pdfFile.exists()) {
                    pdfFile.delete();
                    result = null;
                }
                myHandler.sendEmptyMessage(LOAD_ERROR);
            } finally {
                if (null != fos) {
                    try {
                        fos.flush();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != input) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return result;
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            if (!TextUtils.isEmpty(s)) {
                Message message = new Message();
                Bundle bundle = new Bundle();
                bundle.putString("path", s);
                message.setData(bundle);
                myHandler.sendMessage(message);
            }
        }
    }

    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);
            }
        }
    }

    @Override
    public void onPageChanged(int page, int pageCount) {
        tvPage.setText(getString(R.string.page_count, page, pageCount));
    }


    static class MyHandler extends Handler {

        private WeakReference<PdfReadActivity> weakReference;

        MyHandler(PdfReadActivity activity) {
            weakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            PdfReadActivity activity = weakReference.get();
            int what = msg.what;
            if (null != activity) {
                if (LOAD_ERROR == what) {
                    Toast.makeText(activity, "文件读取失败,请重试", Toast.LENGTH_SHORT).show();
                } else if (LOAD_CANCEL == what) {
                    SharedPreferencesUtils.saveBooleanParam(activity, IS_LOAD_COMPLETE, false);
                }
                Bundle data = msg.getData();
                if (null != data) {
                    String path = (String) data.get("path");
                    SharedPreferencesUtils.saveBooleanParam(activity, IS_LOAD_COMPLETE, true);
                    activity.showPdf(path);
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) {
            SharedPreferencesUtils.saveBooleanParam(this, IS_LOAD_COMPLETE, false);
            task.cancel(true);
        }
        super.onDestroy();
    }
}
 
 
 
 
 //文件工具类
 
 
public class FileUtils {
    public static boolean hasSDCard() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }
 
 
 
 
    public static String getRootFilePath() {
        if (hasSDCard()) {
        // filePath:/sdcard/
            return Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
        } else {
        // filePath: /data/data/
        return Environment.getDataDirectory().getAbsolutePath() + "/data/";
    }
}


[java]  view plain  copy
  1.   

补充:compile 'com.lidong.pdf:android_pdf:1.0.1'

这个是也算是上者的升级版,内部封装好了Retrofit 网络下载,也做了缓存,一次只能缓存一个,主要是通过文件名是否一致来判断,所以喜欢简单的,也可以试试,毕竟一行代码解决很吸引人


二.Android自带PdfRenderer

这个是Google的,对于apk不会增加体积为0,乍看很有诱惑,但是可惜的是最低支持5.0系统,核心是转换成图片然后显示

1.适用场景:同上

2.show code

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/btn_previous"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="上一页" />

    <Button
        android:id="@+id/btn_next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:text="下一页" />

</RelativeLayout>

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class AndroidPdfViewActivity extends AppCompatActivity implements View.OnClickListener {

    /**
     * Key string for saving the state of current page index.
     */
    private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index";

    /**
     * The filename of the PDF.
     */
    private static final String FILENAME = "sample.pdf";


    /**
     * File descriptor of the PDF.
     */
    private ParcelFileDescriptor mFileDescriptor;

    /**
     * Page that is currently shown on the screen.
     */
    private PdfRenderer.Page mCurrentPage;

    /**
     * PDF page index
     */
    private int mPageIndex;

    /**
     * {@link android.graphics.pdf.PdfRenderer} to render the PDF.
     */
    private PdfRenderer mPdfRenderer;
    private ImageView mImageView;
    private Button btnPrevious;
    private Button btnNext;

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (null != mCurrentPage) {
            outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex());
        }
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third_pdf_view);
        mImageView = (ImageView) findViewById(R.id.iv);
        btnPrevious = (Button) findViewById(R.id.btn_previous);
        btnNext = (Button) findViewById(R.id.btn_next);

        btnPrevious.setOnClickListener(this);
        btnNext.setOnClickListener(this);
        mPageIndex = 0;
        // If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
        if (null != savedInstanceState) {
            mPageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        try {
            openRenderer(this);
            showPage(mPageIndex);
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "Error! " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources.
     */
    private void openRenderer(Context context) throws IOException {
        // In this sample, we read a PDF from the assets directory.
        File file = new File(context.getCacheDir(), FILENAME);
        if (!file.exists()) {
            // Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
            // the cache directory.
            InputStream asset = getAssets().open(FILENAME);
            FileOutputStream output = new FileOutputStream(file);
            final byte[] buffer = new byte[1024];
            int size;
            while ((size = asset.read(buffer)) != -1) {
                output.write(buffer, 0, size);
            }
            asset.close();
            output.close();
        }
        mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
        // This is the PdfRenderer we use to render the PDF.
        if (mFileDescriptor != null) {
            mPdfRenderer = new PdfRenderer(mFileDescriptor);
        }
    }

    /**
     * Shows the specified page of PDF to the screen.
     *
     * @param index The page index.
     */
    private void showPage(int index) {
        if (mPdfRenderer.getPageCount() <= index) {
            return;
        }
        // Make sure to close the current page before opening another one.
        if (null != mCurrentPage) {
            mCurrentPage.close();
        }
        // Use `openPage` to open a specific page in PDF.
        mCurrentPage = mPdfRenderer.openPage(index);
        // Important: the destination bitmap must be ARGB (not RGB).
        Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(),
                Bitmap.Config.ARGB_8888);
        // Here, we render the page onto the Bitmap.
        // To render a portion of the page, use the second and third parameter. Pass nulls to get
        // the default result.
        // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
        mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
        // We are ready to show the Bitmap to user.
        mImageView.setImageBitmap(bitmap);
        updateUi();
    }

    /**
     * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources.
     *
     * @throws java.io.IOException When the PDF file cannot be closed.
     */
    private void closeRenderer() throws IOException {
        if (null != mCurrentPage) {
            mCurrentPage.close();
        }
        mPdfRenderer.close();
        mFileDescriptor.close();
    }

    @Override
    protected void onDestroy() {
        try {
            closeRenderer();
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }

    @Override
    protected void onPause() {
        try {
            closeRenderer();
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onPause();
    }

    /**
     * Updates the state of 2 control buttons in response to the current page index.
     */
    private void updateUi() {
        int index = mCurrentPage.getIndex();
        int pageCount = mPdfRenderer.getPageCount();
        btnPrevious.setEnabled(0 != index);
        btnNext.setEnabled(index + 1 < pageCount);
//        setTitle(getString(R.string.app_name_with_index, index + 1, pageCount));
    }

    /**
     * Gets the number of pages in the PDF. This method is marked as public for testing.
     *
     * @return The number of pages.
     */
    public int getPageCount() {
        return mPdfRenderer.getPageCount();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_previous: {
                // Move to the previous page
                showPage(mCurrentPage.getIndex() - 1);
                break;
            }
            case R.id.btn_next: {
                // Move to the next page
                showPage(mCurrentPage.getIndex() + 1);
                break;
            }
        }
    }
}


三.Android PdfViewer

它是基于PdfiumAndroid解码PDF文件

compile 'com.github.barteksc:android-pdf-viewer:2.8.1'

1.适用场景很广,使用简单,唯一缺陷就是会明显增大包体积,所以就不多介绍了



猜你喜欢

转载自blog.csdn.net/leansmall/article/details/80466859