android:加載PDF幾種方法匯總對比

在安卓項目中,加載PDF文件,是一個比較常見的需求披摄。又分為兩大類壳贪,

1.加載網絡PDF

2.加載一個本地靜態(tài)PDF。


查閱資料饮睬,縱觀網上在安卓中打開PDF的各種方式,大致可以分為以下幾類,

1.直接使用第三方軟件打開(包括瀏覽器打開和第三方軟件打開)

如果是在app內部加載PDF文件量九,雖然安卓原生API對于PDF的支持又不是太好,但是各種第三方專門的閱讀或者辦公軟件支持的是很不錯的颂碧,可以通過Intent配置data和type實現(xiàn)荠列,:
其中,在實際需求中又會分為加載本地PDF和網絡PDF的情況载城。

使用瀏覽器打開PDF:(APP外部打開肌似,適用于加載網絡PDF)
public static void openPDFInBrowser(Context context, String url) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Log.w("error", "Activity was not found for intent, " + intent.toString());
        }
    }
使用手機上已安裝的可以打開PDF的第三方軟件來打開PDF:(APP外部打開,適用于加載本地PDF)
(使用這種方式缺點是:手機上如果一個可以打開PDF的軟件诉瓦,那么就尷尬了~)
 public static void openPDFInNative(Context context, String FILE_NAME) {
        File file = new File(context.getExternalCacheDir(),FILE_NAME);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri = Uri.fromFile(file);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(uri, "application/pdf");
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Log.w("URLSpan", "Activity was not found for intent, " + intent.toString());
        }
    }
個人認為川队,這是加載PDF最好的方式。

2.連接Google服務器解析

安卓的WebView不支持PDF解析睬澡,因此通過連接Google的一個服務器轉換成功后返回給WebView顯示固额。但是,但是煞聪,但是呢斗躏,大家都懂的,天朝和Google之間有一道高高的墻昔脯。方法還是貼出來啄糙,作為國際化APP的一種方案馋艺。

mWebView.loadUrl("http://docs.google.com/gview?embedded=true&url="+ pdfUrl);   

3.用第三方庫加載

Github上有一個Java開源項目 https://github.com/barteksc/AndroidPdfViewer ,
這個庫的大致原理,是內置了一個PDF解析器迈套,以流的方式將網絡PDF從網上Down下來捐祠,然后再以流的方式將其還原成PDF展示出來(具體細節(jié)沒關注)。親測中桑李,這個庫每次進入webview頁面都會解析加載一遍PDF踱蛀,如果PDF過大,費時無緩存不說贵白,最致命的問題乃是率拒,

APK包體積會瞬間增大15M左右,

具體原因不明禁荒,估計應該是內置PDF解析器的問題猬膨。于是,此方法被我拋棄了呛伴。


4.使用Moliza開源的Pdf.js

這個JS類庫也是很強大的,配合原生的WebView使用,支持預覽,縮放,翻頁的功能,實現(xiàn)效果和WKWebView沒差勃痴。同樣也有體積問題,全部放到本地apk的話包大小差不多會增加5M左右。但相比上一種方式還是輕量一些:
http://www.jb51.net/article/136364.htm


5.使用安卓自帶的PdfRenderer類加載

如果要求支持的功能不是很多,用安卓提供的PdfRender就可以滿足需求了热康。PdfRender加載多頁的話可以配合ViewPager或者RecyclerView使用.需要注意的是使用PdfRender需要先將PDF文件下載到本地沛申,是線程不安全的,并且API>=21才能使用姐军。因為這種方式是將PDF下載到本地铁材,于是就產生了新問題:占內存。如果是靜態(tài)的PDF文件不大還好奕锌,但是如果是頻繁加載網絡PDF的需求著觉,那就頭疼了,這種方式需要做好定時清理刪除PDF的工作惊暴,否則饼丘,GG。

這里提供的示例是阿里巴巴Android開發(fā)手冊,放到assets目錄下.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MainActivity extends AppCompatActivity {

    private ViewPager vpPdf;

    private LayoutInflater mInflater;
    private ParcelFileDescriptor mDescriptor;
    private PdfRenderer          mRenderer;

    public static final String FILE_NAME = "alibaba.pdf";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mInflater = LayoutInflater.from(this);
        vpPdf =findViewById(R.id.vp_pdf);

        try {
            openRender();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void openRender() throws IOException {

        File file = new File(getExternalCacheDir(), FILE_NAME);
        if (!file.exists()) {
            //復制文件到本地存儲
            InputStream asset = getAssets().open(FILE_NAME);
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024];

            int size;
            while ((size = asset.read(buffer)) != -1) {
                fos.write(buffer, 0, size);
            }

            asset.close();
            fos.close();
        }

        //初始化PdfRender
        mDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
        if (mDescriptor != null) {
            mRenderer = new PdfRenderer(mDescriptor);
        }

        //初始化ViewPager的適配器并綁定
        MyAdapter adapter = new MyAdapter();
        vpPdf.setAdapter(adapter);
    }

    @Override
    protected void onDestroy() {
        //銷毀頁面的時候釋放資源,習慣
        try {
            closeRenderer();
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }

    private void closeRenderer() throws IOException{
        mRenderer.close();
        mDescriptor.close();

    }

    class MyAdapter extends PagerAdapter{

        @Override
        public int getCount() {
            return mRenderer.getPageCount();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view==object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = mInflater.inflate(R.layout.item_pdf, null);

            PhotoView pvPdf = view.findViewById(R.id.iv_pdf);
            pvPdf.enable();

            if (getCount() <= position) {
                return view;
            }

            PdfRenderer.Page currentPage = mRenderer.openPage(position);
            Bitmap bitmap = Bitmap.createBitmap(1080, 1760, Bitmap.Config
                    .ARGB_8888);
            currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
            pvPdf.setImageBitmap(bitmap);
            //關閉當前Page對象
            currentPage.close();

            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            //銷毀需要銷毀的視圖
            container.removeView((View) object);
        }
    }

}

PdfRender的大致調用方式是:

  • 初始化PdfRender,將PDF文件轉換為ParcelFileDescriptor作為入參
  • 通過getPageCount()獲得Pdf的總頁數(shù)
  • 循環(huán)遍歷,通過openPage()獲得一個封裝了當前頁Pdf參數(shù)的內部類Page
  • 創(chuàng)建一個Bitmap對象,,用上步獲取的Page加載,相當于把當前Pdf頁的內容渲染到了Bitmap上
  • 對Bitmap進行你想要的操作,每次循環(huán)結束后關閉當前Page.

大部分都是常規(guī)操作,但要注意兩點:

1,每次循環(huán)創(chuàng)建的Page對象在使用完畢后必須調用close().否則其內部的openPage()判斷會拋異常;
2.Bitmap占用內存較大,如果用ViewPager加載一定要重寫Adapter中的destroyItem(),及時的將需要銷毀的視圖從父容器中移除,否則快速滑動幾頁后會OOM


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末缴守,一起剝皮案震驚了整個濱河市葬毫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屡穗,老刑警劉巖贴捡,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異村砂,居然都是意外死亡烂斋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汛骂,“玉大人罕模,你說我怎么就攤上這事×辈t!?“怎么了淑掌?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝶念。 經常有香客問我抛腕,道長,這世上最難降的妖魔是什么媒殉? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任担敌,我火速辦了婚禮,結果婚禮上廷蓉,老公的妹妹穿的比我還像新娘全封。我一直安慰自己,他們只是感情好桃犬,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布刹悴。 她就那樣靜靜地躺著,像睡著了一般疫萤。 火紅的嫁衣襯著肌膚如雪颂跨。 梳的紋絲不亂的頭發(fā)上敢伸,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天扯饶,我揣著相機與錄音,去河邊找鬼池颈。 笑死尾序,一個胖子當著我的面吹牛,可吹牛的內容都是我干的躯砰。 我是一名探鬼主播每币,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼琢歇!你這毒婦竟也來了兰怠?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤李茫,失蹤者是張志新(化名)和其女友劉穎揭保,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體魄宏,經...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡秸侣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片味榛。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡椭坚,死狀恐怖,靈堂內的尸體忽然破棺而出搏色,到底是詐尸還是另有隱情善茎,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布频轿,位于F島的核電站巾表,受9級特大地震影響,放射性物質發(fā)生泄漏略吨。R本人自食惡果不足惜集币,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翠忠。 院中可真熱鬧鞠苟,春花似錦、人聲如沸秽之。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽考榨。三九已至跨细,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間河质,已是汗流浹背冀惭。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掀鹅,地道東北人散休。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像乐尊,于是被迫代替她去往敵國和親戚丸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,099評論 25 707
  • 用兩張圖告訴你扔嵌,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料限府? 從這篇文章中你...
    hw1212閱讀 12,723評論 2 59
  • 原文來自theNextWeb,作者Jerry Cao痢缎,一位就職于UXPin的內容策略專家胁勺,轉載請先詢問筆者意見并注...
    IrioLee閱讀 2,613評論 1 57
  • 歐洲正在推動對外國投資進行更嚴格的審查,劍指北京牺弄。澳大利亞一直在阻止中國買家收購其戰(zhàn)略資產姻几。在加拿大宜狐,中國對一家主...
    東南道六號閱讀 133評論 0 0
  • 子時心慌 丑時看燈窗 寅時前途茫茫 卯時雞鳴對鏡狀 辰時朝宴杯酒傾上 巳時挽袖流笛悲聲愴 午時持劍起舞琴聲朗朗 未...
    茶歌_6e75閱讀 327評論 0 0