Android应用内在线查看PDF文件

来源:互联网 发布:手机淘宝申请账号注册 编辑:程序博客网 时间:2024/06/16 01:55

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

一.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/";    }}


补充: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.适用场景很广,使用简单,唯一缺陷就是会明显增大包体积,所以就不多介绍了




原创粉丝点击