android pdf框架-10,相册浏览

MupdfViewer 这是最后apk,源码在前面的文章已经贴过了本站下载地址,只是不是最新的.可能不少是旧的内容.

subsampling-scale-image-view这是一个大图片的分块加载的实现.比较不错的.滑动方面我觉得使用flinger的效果比它要流畅,惯性要好.

也有人把这个作成pdf渲染器.但翻页就不好了.

现在的手机相册现在可能使用的是opengl实现的.

本项目中的,自定义flinger在滚动惯性上比其它要强一些.惯性太高,也会看到加载过程,反而会让人觉得慢...

多数的pdf阅读器都会用缓存.下文说到把块的缓存去了,原因之一是无法处理被回收的问题.另一个,缓存如果直接在主线程读取,因为它是同步的,会造成页面卡顿,滚动过程尤其明显.barteksc就是这样的,把它从scroller换成flinger实现滚动,就会明显感觉到卡顿,尤其在放大倍数提升到10倍后,对于barteksc,的10倍还不如我这边缩放4倍大,因为它是以最大的图片去计算的.

所以从这方面来说,我对改造后的效果还是挺满意的.

相册有很多,几乎全部是单张图片的浏览. 并不方便连续的浏览.

需求可能是这样的:

我在微博下了一些长图片,每一张在相册中查看当然可以,能放大,但是比较麻烦.

如果要生成pdf,会占了不少空间,而且照片会增加,比如拍照,会持续拍,总不能一直生成pdf,当然可以使用追加式的.

在浏览目录时,长按菜单,出现相册功能.按时间倒序排列查看.与pdf一样,所有的照片默认是同一个宽.不像barteksc它们都是保留原始宽,这样滑动后,可能容易内容滑出去了.这不是一个阅读器的好的体验方式.因为中间有一张特别宽的图片,会导致内容经常滑出去.

在pdf程序写好以后,我发现,既然生成的pdf可以,我也可以用pdf的浏览方式去查看相册.

相册图片解码速度比pdf还是要快不少的.目前没有针对三星这种拍照方向不对的照片处理.国内已经很少有三星手机了.

由于原来的pdfpage实现的接口,document等接口,添加一种实现即可.

class AlbumViewerActivity extends BaseViewerActivity {
    
    protected ProgressDialog progressDialog;
    
    @Override
    protected DecodeService createDecodeService() {
        return new DecodeServiceBase(new AlbumContext());
    }
    
    protected void loadDocument(String path) {
        progressDialog=new ProgressDialog(this);
        progressDialog.setMessage("Loading");
        progressDialog.show();
        
        AppExecutors.Companion.getInstance().diskIO().execute(() -> {
            decodeService.open(path);
            AppExecutors.Companion.getInstance().mainThread().execute(() -> {
                progressDialog.dismiss();
                documentView.showDocument();
            });
        });
    }
}

对activity作一次重构,把加载文档放到异步线程中,因为这不是加载pdf文档,是加载一个目录下的所有图片,有可能比较耗时.

加一个context

class AlbumContext implements CodecContext {

    public CodecDocument openDocument(String fileName) {
        return AlbumDocument.openDocument(fileName);
    }

    public void setContentResolver(ContentResolver contentResolver) {
    }

    public void recycle() {
    }
}

然后就是文档

class AlbumDocument implements CodecDocument {

    ArrayList<File> files;
    int count = 0;

    private static FileFilter createFileFilter() {
        return pathname -> {
            if (pathname.isHidden()) {
                return false;
            }

            if (pathname.isDirectory())
                return false;
            String fname = pathname.getName().toLowerCase(Locale.ROOT);

            return AdapterUtils.INSTANCE.isImage(fname);
        };
    }

    public static AlbumDocument openDocument(String fname) {
        File[] fileArray = new File(fname).listFiles(createFileFilter());
        ArrayList<File> files = new ArrayList<>(fileArray != null ? Arrays.asList(fileArray) : Collections.<File>emptyList());
        Collections.sort(files, (o1, o2) -> {
            if (o1 == null && o2 == null) {
                return 0;
            }
            if (o1.isDirectory() && o2.isFile()) return -1;
            if (o1.isFile() && o2.isDirectory()) return 1;
            if (o1.lastModified() - o2.lastModified() > 0) {
                return -1;
            } else if (o1.lastModified() - o2.lastModified() < 0) { //jdk7以上需要对称,自反,传递性.
                return 1;
            } else {
                return 0;
            }
        });
        AlbumDocument document = new AlbumDocument(files);
        return document;
    }

    public AlbumDocument(ArrayList<File> files) {
        this.files = files;
        if (null != files) {
            count = files.size();
        }
    }

    public CodecPage getPage(int pageNumber) {
        return AlbumPage.createPage(files.get(pageNumber).getAbsolutePath(), pageNumber);
    }

    public int getPageCount() {
        return count;
    }

    @Override
    protected void finalize() throws Throwable {
        recycle();
        super.finalize();
    }

    public synchronized void recycle() {
    }

    @Override
    public Outline[] loadOutline() {
        return new Outline[0];
    }
}

要过滤出支持解码的图片类型,svg目前不行.

最关键的还是解码部分. 这里对每一块解码都可能重新生成一个decoder,可以优化一下.

class AlbumPage implements CodecPage {

    private long pageHandle = -1;
    int pageWidth;
    int pageHeight;
    private BitmapRegionDecoder decoder;
    private String path;

    static AlbumPage createPage(String fname, int pageno) {
        AlbumPage pdfPage = new AlbumPage(pageno, fname);
        return pdfPage;
    }

    public AlbumPage(long pageno, String fname) {
        this.pageHandle = pageno;
        this.path = fname;
    }

    public int getWidth() {
        if (pageWidth == 0) {
            decodeBound();
        }
        return pageWidth;
    }

    private void decodeBound() {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        pageWidth = options.outWidth;
        pageHeight = options.outHeight;
    }

    public int getHeight() {
   
上一篇:9:00面试,9:06就出来了,问的问题有点变态。。。


下一篇:【MySQL探索之旅】MySQL数据表的增删查改——约束