`

ListView避免多线程加载一个同一资源

阅读更多

当我们的ListView中的Item包含图片,而且这些图片是同一资源,我们用多线程去加载图片,这时候可能就发生了这种情况。

比如线程是人,第一个人去做加载图片到缓存的工作,还没做好时第二个人要这同一张张图,结果缓存还没有这张图,于是第二个人也去加载图片到缓存。。以此类推,同时可能有N个人在加载同一张图,N取决于图片没加载到缓存前,可见的Item数量。

于是针对这种情况进行细化同步,避免发生。

 

//首先需要一个ConcurrentHashMap<String, Boolean>,String表示资源地址如图片地址,Boolean表示是否有线程正在加载。
//之所以用ConcurrentHashMap,是因为它不但是同步的而且效率高于Synchronized和ReenTrantLock.
private ConcurrentHashMap<String, Boolean> mConcurentMap;
//然后需要一个ReentrantLock锁住线程内的关键判断语句。
private ReentrantLock mLock;

 当一个线程没有在缓存找到资源,那么将读取资源,ConcurrentHashMap记录这个资源地址,并且Boolean为true,表示有人在干这个活了,下面的人只要等待干活的人干完就行了。

 

//这是加载图片的线程,当缓存中没找到图片(mBitmapCache.get(path) == null)进入此线程
Thread thread = new Thread() {
       @Override
       public void run() {
           mLock.lock();//锁住关键判断逻辑,避免同一资源多个线程都进入false逻辑(加载图片)
           if (mConcurentMap.get(path) == false) {
               // mConcurentMap添加键值对,表示path这个资源已经有人在加载了
               mConcurentMap.put(path, true);
               mLock.unlock(); //释放锁,下面进入的线程只能进入true的逻辑(等待第一个人做完工作)
               if (path != null && (!path.equals("null"))                                                        && (!"".equals(path))) {
                   //加载图片
                   item.bm = PictureHelper.getCropImage(path, 400, true, 100,mActivity, 7, true);
                   //图片加载完放入缓存Lrucache
                   mBitmapCache.put(path, item.bm);
                   //设置键值对,false表示path这个资源已经加载完,或者没人加载了
                   mConcurentMap.put(path, false);
                } else {
                   item.bm = null;
                   //图片地址无效
                   mConcurentMap.put(path, false);
                }
                Message msg = new Message();
                msg.what = 1;
                handler.sendMessage(msg); 
            } else {
                // 释放锁
                mLock.unlock();
                // 表示有人在加载图片,因此用死循环等待加载完成
                while (true) {
                    // false表示加载完成,此时缓存已有图片,应该跳出循环
                    if (mConcurentMap.get(path) == false) {
                        // Logg.D("other need break cycle");
                        break;
                    }
                }
                // Logg.D("other go out cycle");
                if (mBitmapCache.get(path) != null) {
                    item.bm = mBitmapCache.get(path);
                    Message msg = new Message();
                    msg.what = 2;
                    handler.sendMessage(msg);
                } else {
                    throw new NullPointerException("(mBitmapCache.get(path) == null!");
                }
            }
        }
    };
    executors.execute(thread);

 

0
0
分享到:
评论

相关推荐

    listview优化和异步加载全攻略

    3. 资源复用:例如,对于播放状态的图标,可以只保留一个实例,每次显示时都指向同一资源,避免重复创建。 总结,优化ListView和实现异步加载是提升Android应用性能的关键。通过上述策略,我们可以显著改善ListView...

    Android开发之listview优化+图片异步加载缓存+避免图片显示闪烁

    2.1 **线程管理**:使用AsyncTask、Handler或第三方库如Volley、Retrofit等,在后台线程加载图片,避免阻塞主线程。 2.2 **图片库选择**:推荐使用成熟的图片加载库,如Glide、Picasso或 Fresco。这些库支持内存和...

    多线程加载图片

    "多线程加载图片"这个主题就是针对这一问题,通过利用多线程技术提高用户体验,防止应用因图片加载而变得卡顿。下面将详细阐述实现这一功能的关键知识点。 1. **线程基础**: - **主线程(UI线程)**:负责处理...

    Listview实现分页加载

    1. **防止重复加载**:在加载更多数据之前,应检查是否已有加载更多数据的请求正在进行,以避免同一时间发起多个请求。 2. **设置加载更多项**:在数据集的末尾添加一个特殊的项,表示“加载更多”,当用户滚动到这...

    ListView异步加载网络图片

    总之,ListView异步加载网络图片是一项关键技术,它涉及到Android多线程、内存管理和图片缓存策略。合理地运用这些技术,可以构建出性能优良、用户体验良好的应用。同时,使用SoftReference可以平衡内存使用和图片...

    android listview点击加载更多下拉刷新

    - 在加载更多数据时,为了避免用户看到ListView闪烁,可以先添加一个加载中的占位View,等新数据加载完后再替换。 - 防止过度绘制,避免同一时刻加载过多数据,可以设置ListView的滚动监听,暂停或恢复Adapter的...

    ListView基于AsyncTask实现图片加载(附测试可用图片链接)

    首先,AsyncTask是Android提供的一个轻量级组件,用于在后台线程执行耗时操作,然后在UI线程更新结果。在ListView中加载图片时,我们不能直接在主线程进行,因为这会导致界面冻结,用户体验下降。因此,我们需要在...

    android中listview,gridview加载图片的线程并发解决方案

    此外,还需要合理管理正在执行的任务,避免重复加载同一张图片。例如,在`doInBackground`方法中检查当前任务是否已被取消,或者是否已有相同URL的加载任务正在进行,以此来优化线程使用和资源消耗。 总之,处理...

    Listview图片加载及分页技术

    - ListView是.NET Framework中的一个控件,用于展示数据集,可以以列表、小图标或详细信息等视图显示。 - 它支持多种视图模式,如List、SmallIcon、Tile、Details和Report,便于展示不同类型的数据。 2. **图片...

    安卓开发-Listview分页加载数据.zip

    - **防止重复加载**:确保用户快速滚动时不会重复加载同一页面的数据,这通常通过设置一个标记来实现。 - **预加载**:在用户滚动到接近底部时,可以提前加载下一页数据,以减少用户等待时间。 总之,分页加载是...

    android中listviewgridview加载图片的线程并发解决方案.pdf

    此外,对于用户滑动ListView或GridView时的多线程并发问题,我们需要避免同一时间启动过多的下载任务。一种常见解决方案是使用内存缓存和磁盘缓存来存储已下载的图片,这样在用户滚动回之前看到的图片时,可以直接从...

    AndroidListView异步加载图片乱序问题,原因分析及解决方案.docx

    - **异步加载的问题**:当使用异步线程加载图片时,图片加载完成的时间是不确定的。如果加载完成后视图已经被复用,则该图片将被错误地绑定到新的位置上,导致错位的现象。 **2. 解决方法** - **绑定标识符**:为...

    Android自定义ListView图片从服务端获取

    - 图片加载监听:通过监听图片加载状态,可以避免在ListView滚动时重复加载同一图片。 - 使用AsyncTaskLoader:Loader框架可以帮助我们在后台加载数据,并在数据准备好后通知UI,避免内存泄漏。 5. **占位图和...

    C# ListView显示图像模式 源代码

    在C#编程中,ListView控件是Windows Forms中常用的一个组件,用于展示列表形式的数据。在某些场景下,我们可能需要在ListView中显示图像,比如创建一个类似Acdsee的图片浏览器,这时就需要用到“图像模式”。这个...

    ListView停止滚动开启下载图片.rar

    在getView()方法中,我们应确保只在需要的时候加载图片,避免同一图片被多次加载。 通过以上技术手段,我们可以实现一个流畅且高效的ListView图片加载体验。"ListView停止滚动开启下载图片.rar"中的代码示例可能...

    Volley。fastJson解析网络Json ,多线程显示图片,简单缓存图片,万能适配器,完美解决图片排序混乱问题,完美解决图片多次加载问题

    另外,结合Volley的缓存策略,可以避免同一图片的重复加载。 综上所述,这个项目展示了如何利用Volley进行网络请求和FastJson解析JSON数据,同时结合多线程和图片缓存技术优化用户体验。万能适配器则使得数据绑定...

    android异步加载图片

    1. 使用内存缓存和磁盘缓存:缓存可以避免重复加载同一张图片,提高加载速度。大部分图片加载库都有内置的缓存策略。 2. 图片缩放:原始图片可能很大,直接加载会消耗大量内存,我们需要在加载前根据控件大小进行...

    android的viewpager+fragment+listView图片缓存

    `Universal Image Loader`是一个强大的Android图片加载、缓存库,它提供了线程管理、内存和磁盘缓存策略等功能。以下是如何使用`Universal Image Loader`实现图片缓存的步骤: 1. **集成库**:首先,在项目的`build...

    图文混排 异步加载

    综上所述,"图文混排 异步加载"是Android开发中的关键技能,涉及UI设计、多线程通信、性能优化等多个方面。理解和熟练运用这些技术,可以提升应用的用户体验和性能。在实际项目中,我们应结合Handler、ListView优化...

Global site tag (gtag.js) - Google Analytics