Android相册解决加载大量图片卡顿问题

2023-05-16

Android开发中加载相册是很常用的功能,但相册图片过多正常加载会产生卡顿,即便使用线程异步加载图片卡顿问题依然得不到改善。
正常代码:

public class AlbumAdapter extends ?{
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        if(bitmap!=null){
            线程加载图片
        }
        else
            读取缓存
    }
}

卡顿原因是无论怎样优化读取IO都是费时的工作,adapter又会一次实例多个子项,导致加载的图片过多,内存占用率过高产生了卡顿。
优化代码:

public class AlbumActivity extends AppCompatActivity{
    private RecyclerView mRecyclerView;
    private List<PhotoItem> photoItemList;
    private List<PhotoItem> selectItemList;
    private int[] photoLayout;
    private AlbumAdapter mAdapter;
    private Handler handler;
    private Button submit;
    private GridLayoutManager gridLayoutManager;
    private static final String[] STORE_IMAGES = {
            MediaStore.Images.Media.DISPLAY_NAME, // 显示的名字
            MediaStore.Images.Media.LATITUDE, // 维度
            MediaStore.Images.Media.LONGITUDE, // 经度
            MediaStore.Images.Media._ID, // id
            MediaStore.Images.Media.BUCKET_ID, // dir id 目录
            MediaStore.Images.Media.BUCKET_DISPLAY_NAME, // dir name 目录名字
            MediaStore.Images.Media.DATA//路径
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_album);
        submit = (Button)findViewById(R.id.submit);
        mRecyclerView = (RecyclerView)findViewById(R.id.list);
        gridLayoutManager = new GridLayoutManager(this, 3);
        mRecyclerView.setLayoutManager(gridLayoutManager);
        mRecyclerView.setHasFixedSize(true);
        photoLayout = new int[2];
        photoLayout[0]=(ScreenHelper.getScreenWidth(this) - ScreenHelper.dp2px(this, 20)) / 3 - ScreenHelper.dp2px(this, 10);
        photoLayout[1] = ScreenHelper.dp2px(this, 110);
        gridLayoutManager.findFirstCompletelyVisibleItemPosition();
        initPhoto();
        notifySubmit();
        mAdapter = new AlbumAdapter(mRecyclerView,photoItemList,selectItemList);
        mAdapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(RecyclerView.ViewHolder viewHolder, int position) {
                notifySubmit();
            }
        });

        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                //停止滑动后缓存当前屏幕图片
                if(newState == 0){
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for(int i=gridLayoutManager.findFirstVisibleItemPosition();i<gridLayoutManager.findLastVisibleItemPosition();i++){
                                cacheBitmap(i);
                            }
                        }
                    }).start();
                }
            }
        });

        mRecyclerView.setAdapter(mAdapter);

        handler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                mAdapter.notifyImage((int)msg.obj);
                return false;
            }
        });
    }

    private void initPhoto(){
        photoItemList = new ArrayList<>();
        selectItemList = (List<PhotoItem>)getIntent().getSerializableExtra(FinalHelper.IMAGE_PATH);
        if(selectItemList == null)
            selectItemList = new ArrayList<>();
        String path="";
        for(int i=0;i<selectItemList.size();i++){
            path += selectItemList.get(i).getPath()+",";
        }
        Cursor cursor = MediaStore.Images.Media.query(getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, STORE_IMAGES,"width >0","date_modified desc");
        cursor.moveToNext();
        for (int i = 0; i < cursor.getCount(); i++) {
            PhotoItem photoItem = new PhotoItem(cursor.getInt(3),path.indexOf(cursor.getString(6))!=-1?true:false,cursor.getString(0),cursor.getString(6));
            photoItemList.add(photoItem);
            cursor.moveToNext();
        }

        //从前往后存缓存缩略图  单线程轮播减少内存消耗确保屏幕不卡顿
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<photoItemList.size();i++){
                    cacheBitmap(i);
                }
            }
        }).start();
    }

    //缓存bitmap
    public void cacheBitmap(int position){
        if(CacheManager.get(photoItemList.get(position).getPath())==null){
            Bitmap bitmap = ImageHelper.getSmallCropBitmap(photoItemList.get(position).getPath(), photoLayout[0], photoLayout[1]);
            CacheManager.put(photoItemList.get(position).getPath(),bitmap);
            Message message = new Message();
            message.obj=position;
            handler.sendMessage(message);
        }
    }

    public void notifySubmit(){
        if(selectItemList.size()>0){
            submit.setBackgroundResource(R.drawable.bg_album_submit_enable);
            submit.setText(getString(R.string.submit) + "(" + selectItemList.size() + ")");
            submit.setTextColor(ContextCompat.getColor(this, R.color.white));
            submit.setAlpha(1f);
            submit.setClickable(true);
        }
        else {
            submit.setBackgroundResource(R.drawable.bg_album_submit);
            submit.setTextColor(ContextCompat.getColor(this, R.color.darkgray));
            submit.setAlpha(.8f);
            submit.setText(getString(R.string.submit));
            submit.setClickable(false);
        }
    }

    public void onSubmit(View view){
        Intent intent = new Intent();
        intent.putExtra(FinalHelper.IMAGE_PATH, (Serializable) selectItemList);
        setResult(Activity.RESULT_OK, intent);
        finish();
    }

    public void onBack(View view){
        finish();
    }

    public void onCancel(View view){
        finish();
    }


}

在读取相册的基本数据后,采用单线程轮播的方式顺序缓存图片缩率图,这样便解决了卡顿问题,在配合缓存类,再次加载相册就可以瞬间全部加载完毕,推荐使用开源的第三方库DiskLruCache实现图片的缩略图缓存。
QQ相册初次加载相册图片也是一张一张的,仿QQ相册实例:http://blog.csdn.net/lishengko/article/details/56495553

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android相册解决加载大量图片卡顿问题 的相关文章

随机推荐

  • @AliasFor 注解使用规则

    64 AliasFor 顾名思义 xff0c 表示别名 1 它可以注解到自定义注解的两个属性上 xff0c 表示这两个互为别名 2 注解是可以继承的 xff0c 但是不能用来继承父注解的某个属性值 xff0c 可以通过在子注解对于的属性上加
  • Docker Desktop修改默认安装路径?

    原理 xff1a 建立一个目录的软链接 用管理员身份打开cmd窗口 xff0c 然后运行命令 xff1a mklink j 34 C Program Files Docker 34 34 D Program Files Docker 34
  • java web项目打包成exe安装程序

    需求 xff1a 由于java web项目 xff0c 需要依赖mysql数据库 tomcat容器 jdk等 xff0c 部署需要一定技术支持才能够完成 xff0c 操作繁琐 xff0c 希望简化 目标 xff1a 制作一个exe一键安装相
  • http 请求参数包含? & 处理

    escape encodeURI encodeURIComponent 区别详解 JavaScript中有三个可以对字符串编码的函数 xff0c 分别是 xff1a escape encodeURI encodeURIComponent x
  • 多个项目共用一个redis

    redis 数据库是由一个整数索引标识 xff0c 而不是由一个数据库名称 默认情况下连接到数据库0 因此多个项目如果配置不做修改都会使用0号数据库 xff0c 会发生冲突 所以 每个项目配置不同的 database 即可解决
  • LoadRunner中参数化技术详解

    LoadRunner中参数化技术详解 LoadRunner在录制脚本的时候 xff0c 只是忠实的记录了所有从客户端发送到服务器的数据 xff0c 而在进行性能测试的时候 xff0c 为了更接近真实的模拟现实应用 xff0c 对于某些信息需
  • 23种设计模式类图

    下边是23种设计模式的类图大汇总 xff0c 23种设计模式解析请移步 http blog csdn net qq 25827845 article details 52932234 1 创建类模式 2 行为类模式 3 结构类模式
  • navicat 复制表结构到word文档做数据库设计格式问题解决

    需求 xff1a 写数据库设计文档 xff0c 需要设计数据字典 xff0c 贴表结构 xff0c 如果是几百张表 一个个填工作量很大 解决方案 xff1a 1 sql查询所有字段 2 整体复制到excel 3 拆分表 xff0c 调整列项
  • vue图片压缩上传组件修改

    判断逻辑 大于200KB 压缩上传 xff0c 否则不做处理上传原始图片 1 安装插件 yarn add image conversion 2 引入 import compressAccurately from 39 image conve
  • new ScriptEngineManager().getEngineByName(“js“)返回null

    问题出现的场景 xff1a 本地开发和生产环境都没问题 xff0c 测试环境 用的docker 报空指针 new ScriptEngineManager getEngineByName 34 js 34 返回null js替换 JavaSc
  • vue a-collapse的默认全部展开

    思路 xff1a activekey的值为默认展开的项 xff0c 要想全部展开 xff0c 就得把所有的key值都加到 activekey中 如下例子 xff0c activekey 61 39 1 39 默认展开第一个 要想全部展开就需
  • 软件工程——软件结构图设计(变换分析设计、事务分析设计、混合流设计)

    结构化设计 SD 是以结构化分析 SA 产生的数据流图为基础 xff0c 将数据流图按一定的步骤映射成软件结构图 SC 一 数据流的类型 结构化设计的目的是要把数据流图映射成软件结构 xff0c 根据数据流的特性 xff0c 一般可分为变换
  • Linux下Appium+Python移动应用自动化测试实战之“Android Emulator Headless”

    腊月二十九写的那篇手把手定位元素编写用例的文章 xff0c 没想到在4天的时间获得了2000多的阅读量 作为一个成熟的概念和框架 xff0c 没想到热度竟然还这么高 博主果断放弃了今天下午的10公里越野 xff0c 加快推出Android
  • Hbase系列---内置过滤器

    HBase为筛选数据提供了一组过滤器 xff0c 通过这个过滤器可以在HBase中的数据的多个维度 xff08 行 xff0c 列 xff0c 数据版本 xff09 上进行对数据的筛选操作 xff0c 也就是说过滤器最终能够筛选的数据能够细
  • org.apache.maven.plugin.war.WarMojo

    maven工程pom文件报错 xff0c org apache maven plugin war WarMojo 在pom文件中的 lt build gt 标签内加入如下代码 lt plugins gt lt plugin gt lt gr
  • js实现各种进制的转换

    使用Integer toString 进制数即可
  • 浅谈软件性能测试中关键指标的监控与分析

    浅谈软件性能测试中关键指标的监控与分析 一 软件性能测试需要监控哪些关键指标 xff1f 软件性能测试的目的主要有以下三点 xff1a 评价系统当前性能 xff0c 判断系统是否满足预期的性能需求 寻找软件系统可能存在的性能问题 xff0c
  • 最全面的MySQL知识点总结

    前言 最近在回顾之前学的知识点 xff0c mysql部分涉及的东西很多 xff0c 所以想写写文章记录一些重要的知识点 xff0c 方便以后回顾 xff0c 同时也分享给大家 xff0c 如果文章中有描述的不对或不足的地方 xff0c 欢
  • Debian和Ubuntu作为程序员桌面系统,推荐哪一个

    Ubuntu买VPS时有CentOS Debian Ubuntu三种操作系统可以选择 xff0c Linux下哪种系统更好是很多新人都会遇到的问题 xff0c 在此 xff0c 我们分析一下Ubuntu CentOS及Debian各自的性能
  • Android相册解决加载大量图片卡顿问题

    Android开发中加载相册是很常用的功能 xff0c 但相册图片过多正常加载会产生卡顿 xff0c 即便使用线程异步加载图片卡顿问题依然得不到改善 正常代码 xff1a span class hljs keyword public spa