接着上一篇的博客,在搜索出手机内的.pdf格式文件后,实现pdf文件的预览的方式有很多,
https://github.com/barteksc/AndroidPdfViewer 功能很强大, 使用也比较广, 亲测可以使用. 唯一的缺点 :添加到项目中 会使apk增加10M左右, 这是最不能接受的, 故弃用.
项目地址: https://github.com/voghDev/PdfViewPager 可加载assets/SD卡/URL(在线预览) , 优点: 使用比较方便, 也不大
项目地址:GitHub - mozilla/pdf.js: PDF Reader in JavaScript
是将pdf.js和相关的文件全部下载下来并拷贝的工程中的assets目录,apk会增加4M左右
项目地址:腾讯浏览服务
这种方式是实现本地预览,把pdf文件下载到本地或直接加载本地的pdf文件
优点:使用方便,集成简单,包不大,可以远程依赖(ps:本文采用的是这种方式)
缺点:不能很好地支持部分64手机,Androidx兼容也不是很好.
//跳转到文件预览 pdfAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { @Override public void onItemClick(BaseQuickAdapter adapter, View view, int position) { String fileUrl = Objects.requireNonNull(pdfAdapter.getItem(position)).getFilePath(); String fileName = Objects.requireNonNull(pdfAdapter.getItem(position)).getFileName(); PDFPreViewActivity.actionStart(PDFSearchActivity.this, fileUrl, fileName); } });
/** * @作者: njb * @时间: 2019/9/11 20:31 * @描述: pdf文件预览 */ public class PDFPreViewActivity extends AppCompatActivity implements TbsReaderView.ReaderCallback { private TbsReaderView mTbsReaderView; private String mFileName; private TextView tv_download; private long mRequestId; private DownloadObserver mDownloadObserver; private ProgressBar progressBar_download; private DownloadManager mDownloadManager; private String fileName; private String fileUrl; private String TAG = PDFPreViewActivity.class.getSimpleName(); private RelativeLayout rootRl; private TextView tv_title; private ImageView iv_back; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pdf_preview); initIntent(); initTbsReaderView(); mTbsReaderView = new TbsReaderView(this, this); rootRl.addView(mTbsReaderView, new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); if ((fileUrl == null) || (fileUrl.length() <= 0)) { Toast.makeText(PDFPreViewActivity.this, "获取文件url出错了", Toast.LENGTH_SHORT).show(); return; } mFileName = PDFUtil.parseName(fileUrl); requestPermission(); isDown(); } private void initIntent() { if (getIntent() != null && getIntent().getExtras() != null) { fileUrl = getIntent().getExtras().getString("fileUrl"); fileName = getIntent().getExtras().getString("fileName"); } } //初始化TbsReaderView 5-3 private void initTbsReaderView() { rootRl = findViewById(R.id.rl_tbsView); tv_download = findViewById(R.id.tv_download); progressBar_download = findViewById(R.id.progressBar_download); tv_title = findViewById(R.id.tv_title); tv_title.setText("PDF文件预览"); iv_back = findViewById(R.id.iv_back); iv_back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private void requestPermission() { RxPermissions rxPermissions = new RxPermissions(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { rxPermissions.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) .subscribe(new Consumer() { @Override public void accept(Permission permission) { if (permission.granted) { // 用户已经同意该权限 Log.d(TAG, permission.name + " is granted."); } else if (permission.shouldShowRequestPermissionRationale) { // 用户拒绝了该权限,没有选中『不再询问』(Never ask again),那么下次再次启动时,还会提示请求权限的对话框 Log.d(TAG, permission.name + " is denied. More info should be provided."); } else { // 用户拒绝了该权限,并且选中『不再询问』 Log.d(TAG, permission.name + " is denied."); } } }); } } private void isDown() { if (isLocalExist() || fileUrl.contains("storage")) { tv_download.setText("打开文件"); tv_download.setVisibility(View.GONE); displayFile(); } else { if (!fileUrl.contains("http")) { new AlertDialog.Builder(PDFPreViewActivity.this) .setTitle("温馨提示:") .setMessage("文件的url地址不合法哟,无法进行下载") .setCancelable(false) .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { return; } }).create().show(); } startDownload(); } } @TargetApi(Build.VERSION_CODES.GINGERBREAD) private void queryDownloadStatus() { DownloadManager.Query query = new DownloadManager.Query() .setFilterById(mRequestId); Cursor cursor = null; try { cursor = mDownloadManager.query(query); if (cursor != null && cursor.moveToFirst()) { // 已经下载的字节数 long currentBytes = cursor .getLong(cursor .getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); // 总需下载的字节数 long totalBytes = cursor .getLong(cursor .getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); // 状态所在的列索引 int status = cursor.getInt(cursor .getColumnIndex(DownloadManager.COLUMN_STATUS)); tv_download.setText("下载中...(" + PDFUtil.FormetFileSize(currentBytes) + "/" + PDFUtil.FormetFileSize(totalBytes) + ")"); // 将当前下载的字节数转化为进度位置 int progress = (int) ((currentBytes * 1.0) / totalBytes * 100); progressBar_download.setProgress(progress); Log.i("downloadUpdate: ", currentBytes + " " + totalBytes + " " + status + " " + progress); if (DownloadManager.STATUS_SUCCESSFUL == status && tv_download.getVisibility() == View.VISIBLE) { tv_download.setVisibility(View.GONE); tv_download.performClick(); if (isLocalExist()) { tv_download.setVisibility(View.GONE); progressBar_download.setVisibility(View.GONE); displayFile(); } } } } finally { if (cursor != null) { cursor.close(); } } } /** * 加载显示文件内容 */ private void displayFile() { Bundle bundle = new Bundle(); if (isLocalExist()) { bundle.putString("filePath", getLocalFile().getPath()); } if (fileUrl.contains("storage")) { bundle.putString("filePath", fileUrl); } bundle.putString("tempPath", Environment.getExternalStorageDirectory().getPath()); boolean result = mTbsReaderView.preOpen(PDFUtil.getFileType(mFileName), false); if (result) { mTbsReaderView.openFile(bundle); } else { File file = new File(getLocalFile().getPath()); if (file.exists()) { Intent openintent = new Intent(); openintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); String type = PDFUtil.getMIMEType(file); // 设置intent的data和Type属性。 openintent.setDataAndType(Uri.fromFile(file), type); // 跳转 startActivity(openintent); finish(); } } } /** * 下载文件 */ @SuppressLint("NewApi") private void startDownload() { mDownloadObserver = new DownloadObserver(new Handler()); getContentResolver().registerContentObserver( Uri.parse("content://downloads/my_downloads"), true, mDownloadObserver); mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); //将含有中文的url进行encode String mFileUrl = toUtf8String(fileUrl); try { DownloadManager.Request request = new DownloadManager.Request( Uri.parse(mFileUrl)); request.setDestinationInExternalPublicDir(Constants.DOWNLOAD_PDF_PATH, mFileName); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); mRequestId = mDownloadManager.enqueue(request); } catch (Exception e) { e.printStackTrace(); } } /** * 跳转页面 * * @param context * @param fileUrl 文件url * @param fileName 文件名 */ public static void actionStart(Context context, String fileUrl, String fileName) { Intent intent = new Intent(context, PDFPreViewActivity.class); intent.putExtra("fileUrl", fileUrl); intent.putExtra("fileName", fileName); context.startActivity(intent); } /** * 是否为本地文件 * * @return */ private boolean isLocalExist() { return getLocalFile().exists(); } /** * 本地文件目录 * * @return */ private File getLocalFile() { return new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), mFileName); } @Override public void onCallBackAction(Integer integer, Object o, Object o1) { } private class DownloadObserver extends ContentObserver { private DownloadObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange, Uri uri) { queryDownloadStatus(); } } @Override protected void onDestroy() { super.onDestroy(); mTbsReaderView.onStop(); if (mDownloadObserver != null) { getContentResolver().unregisterContentObserver(mDownloadObserver); } } }
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' //Rx权限 implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar' implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.40' implementation 'androidx.recyclerview:recyclerview:1.0.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' implementation 'io.reactivex.rxjava2:rxjava:2.2.3' implementation "com.tencent.tbs.tbssdk:sdk:43697"
ndk { abiFilters "armeabi", "armeabi-v7a", "x86", "mips" }
如果不指定so的目录,默认就会默认匹配main下的jniLibs目录:
使用远程依赖的方式加载 ,目前Androidx加载第一次可能会失败,多加载几次就好了.
PDFSearch: Android实现手机内PDF文件搜索
PDFSearch.zip-Android文档类资源-CSDN下载