美文网首页
Android #26 下载文件并查看

Android #26 下载文件并查看

作者: 喜欢书的女孩 | 来源:发表于2020-11-12 16:42 被阅读0次
    image

    目录:

    1. 功能需求--分析
    2. 具体实现--动手
    3. 源码分析--优化
    4. 造轮子--demo
    5. 总结

    1. 功能需求--分析


    文字描述:点击 Button 下载 pdf 文件,并在应用内显示。

    具体展示:

    image

    思考实现方式:
    [1] 文件下载--AsyncHttpClient;
    [2] 应用内打开 pdf 文件 -- pdfviewpager;
    尝试过 android-pdf-viewer 开源库,对 assets 目录下的文件打开很友好,但是对于下载后显示 pdf 文件有时会闪退。
    也尝试过 TBS SDK , 对于异常情况显示出一片空白,最终用了pdfviewpager ,终于可以了。

    2. 具体实现--动手


    2.1 add compile in your build.gradle

    compile 'es.voghdev.pdfviewpager:library:1.0.6'

    2.2 use it in your Activity

    [ 1、Button 点击]
     case R.id.btn_download:
                       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            Intent intent = new Intent(FlightCertificateInfoActivity.this, WatchPDFActivity.class);
                            intent.putExtra("etno", etNo);
                            startActivity(intent);
                        } else {
                            loadPdf(etNo);
                        }
                    break;
    
    [2、WatchPDFActivity.class]
    
    import android.annotation.TargetApi;
    import android.app.ProgressDialog;
    import android.graphics.Bitmap;
    import android.graphics.pdf.PdfRenderer;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.ParcelFileDescriptor;
    import android.support.v4.app.FragmentActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.Toast;
    
    import com.jiuair.booking.R;
    import com.jiuair.booking.tools.AsyncHttpUtils;
    import com.jiuair.booking.tools.ViewTool;
    import com.loopj.android.http.AsyncHttpResponseHandler;
    import com.loopj.android.http.RequestParams;
    
    import org.apache.http.Header;
    
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public class WatchPDFActivity extends FragmentActivity implements View.OnClickListener {
    
        //    private PDFView pdfView;
        private ImageView mImageView;
        private ParcelFileDescriptor mFileDescriptor;
        private PdfRenderer mPdfRenderer;
        private PdfRenderer.Page mCurrentPage;
        private Button mButtonPrevious;
        private Button mButtonNext;
        private LinearLayout ll_1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_watch_pdf);
            mImageView = (ImageView) findViewById(R.id.image);
            ll_1 = (LinearLayout) findViewById(R.id.ll_1);
    //        pdfView = (PDFView) findViewById(R.id.pdfView);
            mButtonPrevious = (Button) findViewById(R.id.previous);
            mButtonNext = (Button) findViewById(R.id.next);
            // Bind events.
            mButtonPrevious.setOnClickListener(this);
            mButtonNext.setOnClickListener(this);
            String id = getIntent().getStringExtra("id");
            String abpno = getIntent().getStringExtra("abpno");
            loadPdf(id, abpno);
        }
    
        /**
         * @param etno
         * @param abpno 下载并打开pdf文件
         */
        private void loadPdf(String id, String abpno) {
            String url = "/downloadFile";
            RequestParams params = new RequestParams();
            params.put("id", id);
            final ProgressDialog layerMask = ViewTool.showLayerMask(WatchPDFActivity.this);
            AsyncHttpUtils.get(url, params, new AsyncHttpResponseHandler() {
                @Override
                public void onStart() {
                    // called before request is started
                    Log.e("ATG", "开始获取pdf》》");
                }
    
                @Override
                public void onSuccess(int statusCode, Header[] headers,
                                      byte[] response) {
                    layerMask.dismiss();
                    comLoad(response);
    
                }
    
                @Override
                public void onFailure(int statusCode, Header[] headers,
                                      byte[] errorResponse, Throwable e) {
                    e.printStackTrace();
                    Toast.makeText(WatchPDFActivity.this, "PDF打开失败", Toast.LENGTH_SHORT).show();
                    WatchPDFActivity.this.finish();
                    //called when response HTTP status is "4XX" (eg. 401, 403, 404)
                }
    
                @Override
                public void onRetry(int retryNo) {
                    // called when request is retried
                }
            });
        }
    
        /**
         * @param response 普通的下载pdf到本地然后再打开pdf
         */
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        private void comLoad(byte[] response) {
            BufferedOutputStream bos = null;
            FileOutputStream fos = null;
            File file = null;
            try {
    
                if (Environment.getExternalStorageState().equals(
                        Environment.MEDIA_MOUNTED)) {
                    String fileName = Environment.getExternalStorageDirectory() + "/cxy/" + "resume.pdf";
                    file = new File(fileName);
                    // 目录不存在创建目录
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    fos = new FileOutputStream(file);
                    bos = new BufferedOutputStream(fos);
                    bos.write(response);
    
                    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);
                    }
    
                    showPage(0);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
                Toast.makeText(WatchPDFActivity.this, "PDF打开失败", Toast.LENGTH_SHORT).show();
                WatchPDFActivity.this.finish();
            } finally {
                try {
                    if (bos != null) {
                        bos.close();
                    }
                    if (fos != null) {
                        fos.close();
                    }
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        protected void onDestroy() {
            super.onDestroy();
            try {
                closeRenderer();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        private void closeRenderer() throws IOException {
            if (null != mCurrentPage) {
                mCurrentPage.close();
            }
            if (null != mPdfRenderer)
                mPdfRenderer.close();
            if (null != mFileDescriptor)
                mFileDescriptor.close();
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        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();
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        private void updateUi() {
            int index = mCurrentPage.getIndex();
            int pageCount = mPdfRenderer.getPageCount();
            mButtonPrevious.setEnabled(0 != index);
            mButtonNext.setEnabled(index + 1 < pageCount);
            if (pageCount <= 1) {
                ll_1.setVisibility(View.GONE);
            } else {
                ll_1.setVisibility(View.VISIBLE);
            }
        }
    
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.previous: {
                    // Move to the previous page
                    showPage(mCurrentPage.getIndex() - 1);
                    break;
                }
                case R.id.next: {
                    // Move to the next page
                    showPage(mCurrentPage.getIndex() + 1);
                    break;
                }
            }
        }
    }
    
    

    3. 框架分析--优化


    3.1 android-async-http
    需求中的 pdf 文件一般是一页,大小为 23 kb,属于小文件了,而且整个项目使用的是 android-async-http 框架,所以就用了。但如果是大文件,考虑到网络问题,可能有需要暂停、或者有 wifi 了再下载的情况,那么就应该用 HttpURLConnection 实现断点续传,AsyncTask<String, Integer, Boolean>异步管理下载文件 。

    3.2 pdfviewpager
    如果需求没有指定一定要在应用内打开,更优化的操作步骤是 [1] 判断用户手机是否有安装 wps 之类的文件查看器,[2] 如果有则调用 WPS 等应用打开,反之则按上述步骤,先判断文件是否存在,[3] 存在则直接打开,反之下载后再打开。

    4. 造轮子--demo


    demo 地址

    5. 总结


    最近看了一本书《不敢止步(一个软件工匠的12年)》,作者大四那份工作的历程的感悟让我产生巨大的共鸣,从毕业到现在有快1年了,事情经历得多了就会有迷惑,掉坑里多了就会去反思,愿不负 cxy 这个名字!

    文章是 Android 面向需求开发系列中的一文,更多相关文章请关注。如若有什么问题,也可以通过扫描二维码发消息给我。转载请注明出处,谢谢!

    image

    作者:Emily CH
    2019年3月7日

    相关文章

      网友评论

          本文标题:Android #26 下载文件并查看

          本文链接:https://www.haomeiwen.com/subject/omiavktx.html