资讯专栏INFORMATION COLUMN

android 实现类似微信缓存和即时更新好友头像

instein / 2709人阅读

摘要:引言使用微信时我们会发现,首次进入微信的好友列表时,会加载好友头像,但是再次进入时,就不用重新加载了,而且其他页面都不用重新加载,说明微信的好友头像是缓存在本地的,然后好友修改头像后,又会及时的更新,这个功能是如何实现的呢,我们来分析一下分

引言

使用微信时我们会发现,首次进入微信的好友列表时,会加载好友头像,但是再次进入时,就不用重新加载了,而且其他页面都不用重新加载,说明微信的好友头像是缓存在本地的,然后好友修改头像后,又会及时的更新,这个功能是如何实现的呢,我们来分析一下

分析

关于头像缓存的实现

头像是网络图片,而且数据量较大,如果用我们常用的SharedPreferences将头像以Bitmap的形式存储,势必会造成OOM,这个方法是行不通的,我们存储的只能是图片的地址,但是如果只存储地址的话,要转化成图片,还是要通过网络请求重新加载,达不到我们要求的效果,所以我们需要在磁盘中多带带开辟一块空间,将头像以Bitmap的形式进行存储,如何实现呢?其实关于网络图片的缓存,有很多开源的第三方框架,比较可靠好用的如xUtils,Glide,volley,Universal-Image-Loader,Picasso,Fresco等等。

下面我们以常用的xUtils为例
首先对BitmapUtils的实例化,对于磁盘缓存路径,磁盘缓存空间大小,内存缓存的空间大小,内存缓存百分比可以自定义,也可以使用默认配置,代码如下:

 /**
 * @param context 上下文
 */
public BitmapUtils(Context context) {
    this(context, null);
}

/**
 * @param context 上下文
 * @param diskCachePath 磁盘高速缓存路径
 */
public BitmapUtils(Context context, String diskCachePath) {
    if (context == null) {
        throw new IllegalArgumentException("context may not be null");
    }

    this.context = context.getApplicationContext();
    globalConfig = BitmapGlobalConfig.getInstance(this.context, diskCachePath);
    defaultDisplayConfig = new BitmapDisplayConfig();
}

/**
 * 
 * @param context 上下文
 * @param diskCachePath 磁盘高速缓存路径
 * @param memoryCacheSize 内存缓存空间大小
 */
public BitmapUtils(Context context, String diskCachePath, int memoryCacheSize) {
    this(context, diskCachePath);
    globalConfig.setMemoryCacheSize(memoryCacheSize);
}

/**
 * 
 * @param context 上下文
 * @param diskCachePath 磁盘高速缓存路径
 * @param memoryCacheSize 内存缓存空间大小
 * @param diskCacheSize 磁盘高速缓存空间大小
 */
public BitmapUtils(Context context, String diskCachePath, int memoryCacheSize, int diskCacheSize) {
    this(context, diskCachePath);
    globalConfig.setMemoryCacheSize(memoryCacheSize);
    globalConfig.setDiskCacheSize(diskCacheSize);
}

/**
 * 
 * @param context 上下文
 * @param diskCachePath 磁盘高速缓存路径
 * @param memoryCachePercent 内存缓存百分比
 */
public BitmapUtils(Context context, String diskCachePath, float memoryCachePercent) {
    this(context, diskCachePath);
    globalConfig.setMemCacheSizePercent(memoryCachePercent);
}
     /**
 * 
 * @param context 上下文
 * @param diskCachePath  磁盘高速缓存路径
 * @param memoryCachePercent 内存缓存百分比
 * @param diskCacheSize 磁盘缓存空间大小
 */
public BitmapUtils(Context context, String diskCachePath, float memoryCachePercent, int diskCacheSize) {
    this(context, diskCachePath);
    globalConfig.setMemCacheSizePercent(memoryCachePercent);
    globalConfig.setDiskCacheSize(diskCacheSize);
}

一般情况下,我们只需要使用默认配置就可以了,即
BitmapUtils bitmap = new BitmapUtils(context);
然后对图片的缓存和显示

 /**
 * 根据图片路径,显示到具体的View上
 * @param container 要把图片显示到的View
 * @param uri 图片路径
 */
public  void display(T container, String uri) {
    display(container, uri, null, null);
}

/**
 * 根据图片路径,显示到具体的View上
 * @param container 要把图片显示到的View
 * @param uri 图片路径
 * @param displayConfig
 */
public  void display(T container, String uri, BitmapDisplayConfig displayConfig) {
    display(container, uri, displayConfig, null);
}

/**
 * 根据图片路径,显示到具体的View上
 * @param container 要把图片显示到的View
 * @param uri 图片路径
 * @param callBack 加载过程回调各种状态
 */
public  void display(T container, String uri, BitmapLoadCallBack callBack) {
    display(container, uri, null, callBack);
}   
 
 /**
 * 根据图片路径,显示到具体的View上
 * @param container 要把图片显示到的View
 * @param uri 图片路径
 * @param displayConfig 位图显示配置
 * @param callBack
 */
public  void display(T container, String uri, BitmapDisplayConfig displayConfig, BitmapLoadCallBack callBack) {
    if (container == null) {
        return;
    }

    if (callBack == null) {
        callBack = new DefaultBitmapLoadCallBack();
    }

    if (displayConfig == null || displayConfig == defaultDisplayConfig) {
        displayConfig = defaultDisplayConfig.cloneNew();
    }
    // Optimize Max 
    BitmapSize size = displayConfig.getBitmapMaxSize();SizedisplayConfig.setBitmapMaxSize(BitmapCommonUtils.optimizeMaxSizeByView(container, size.getWidth(), size.getHeight()));

    container.clearAnimation();

    if (TextUtils.isEmpty(uri)) {
        callBack.onLoadFailed(container, uri, displayConfig.getLoadFailedDrawable());
        return;
    }

    // start loading
    callBack.onPreLoad(container, uri, displayConfig);

    // find bitmap from mem cache.
    Bitmap bitmap = globalConfig.getBitmapCache().getBitmapFromMemCache(uri, displayConfig);

    if (bitmap != null) {
        callBack.onLoadStarted(container, uri, displayConfig);
        callBack.onLoadCompleted(
                container,
                uri,
                bitmap,
                displayConfig,
                BitmapLoadFrom.MEMORY_CACHE);
    } else if (!bitmapLoadTaskExist(container, uri, callBack)) {

        final BitmapLoadTask loadTask = new BitmapLoadTask(container, uri, displayConfig, callBack);

        // get executor
        PriorityExecutor executor = globalConfig.getBitmapLoadExecutor();
        File diskCacheFile = this.getBitmapFileFromDiskCache(uri);
        boolean diskCacheExist = diskCacheFile != null && diskCacheFile.exists();
        if (diskCacheExist && executor.isBusy()) {
            executor = globalConfig.getDiskCacheExecutor();
        }
        // set loading image
        Drawable loadingDrawable = displayConfig.getLoadingDrawable();
        callBack.setDrawable(container, new AsyncDrawable(loadingDrawable, loadTask));

        loadTask.setPriority(displayConfig.getPriority());
        loadTask.executeOnExecutor(executor);
    }
}

从这段代码中我们可以看到,当要加载某张图片时,会根据图片地址进行查找是否有对应的bitmap缓存图片,如果有就直接引用缓存,如果没有就加载并缓存,所以我们对图片的缓存只需要实现以上方法就可以了,而且只要设置相同的缓存路径,就可以实现一个页面缓存后,其他页面有相同图片也可以调用。那么缓存之后,好友更新头像,又是怎么做到即时更新的呢?

缓存后如何实现即时更新头像

根据查阅的资料,可以归结为以下几种实现方式:
1.在服务器返回用户数组时多加一个字段头像最后一次修改时间或者修改过几次等标志符,与缓存进行比较,是否有变化
2.利用图片的checkSum来实现,如果check到这个数字有变化,就会自动去更新
3.利用socket监听,当好友头像更新时候首先会告诉服务器,服务器将变化通知推送到所有好友,好友监听收到通知后自动更新
第一种方法和第二种方法本质是一致的,通过请求服务器的数据与本地缓存进行对比,是由客户端处理的,第三种方法的话你换一次头像就要服务器去提醒你的所有好友一遍,服务器压力会不会比较大
仔细去研究一下微信,就会发现,当好友头像修改后,如果你停留在某个页面,进入的这个页面是之前进入过的,还没有销毁,头像是不会改变的,你需要打开一个新的页面或者重新进入微信,才会更新头像,由此看出,微信并不是用的第三种方式,而是采用了前两种方式的实现原理,只有在创建一个Activity或fragment时,调用接口,读取服务器数据时才会更新头像

总结

通过以上的分析,我们基本捋清了思路,要实现类似微信的缓存和更新还有头像,先是在磁盘开辟一个空间,用于读写头像的Bitmap,然后创建页面时,读取服务器数据和本地缓存进行比较,如果有变化就进行更新

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/13402.html

相关文章

  • 基于Bmob的Android即时通讯应用源码解析

    摘要:今天给大家分享系列干货基于的即时通讯应用源码,以后每周都会更新和最新的应用源码。因为百度地图官网上的目前最新的和我之前用过的很不一样,新版百度地图进行了重构和优化,很多之前熟知的都改掉了。 今天给大家分享系列干货:基于Bmob的Android即时通讯应用源码,以后每周都会更新sdk和最新的应用源码。目前Android版已更新到V1.0.5版本。IOS端已推出V1.0.0版本。(由于有图...

    hiyayiji 评论0 收藏0
  • Android-IM从零开始开发一个即时通讯项目

    摘要:关于聊天室项目聊天室项目,也被称为即时通讯。可以满足一个即时通讯类的绝大部分功能。极光官方提供的有即时通讯,包括等都实现了,只需要简单配置就可以用。其中用的最多的是极光,不仅仅是依赖于极光即时通讯服务,后期还会引入统计分享等相关的。 关于聊天室项目 聊天室项目,也被称为即时通讯(IM)。 其原理是服务器是一直在启动状态的线程,不断的从客户端(App)获取消息,收到消息后,进行类型和发送...

    CarlBenjamin 评论0 收藏0
  • 从零开始开发一个即时通讯项目

    摘要:关于聊天室项目聊天室项目,也被称为即时通讯。可以满足一个即时通讯类的绝大部分功能。其中用的最多的是极光,不仅仅是依赖于极光即时通讯服务,后期还会引入统计分享等相关的。 关于聊天室项目 聊天室项目,也被称为即时通讯(IM)。 其原理是服务器是一直在启动状态的线程,不断的从客户端(App)获取消息,收到消息后,进行类型和发送目标判断,以发送到群组或者单聊的方式,客户端收到消息后进行界面的展...

    Zack 评论0 收藏0
  • 微信小程序开发中的二三事之网易云信IMSDK DEMO

    摘要:传统的网页编程采用的三剑客来实现,在微信小程序中同样有三剑客。观察者模式不难实现,重点是如何在微信小程序中搭配其特有的生命周期来使用。交互事件传统的事件传递类型有冒泡型与捕获型,微信小程序中自然也有。 本文由作者邹永胜授权网易云社区发布。 简介为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程。用产品的话说就是: 云信 IM 小程序 S...

    weij 评论0 收藏0
  • 图片处理工具

    摘要:但是我们还是发现至少有两个问题,以为例,第一,当需求变动,你最全面详解图像处理的最重要类之一。将图片存储到一个特殊的区域,避免了。 Android7.0 完美适配——FileProvider 拍照裁剪全解析 适配 android7.0 中的拍照相册裁剪功能 使用 photoView 实现可点击放大到全屏显示的控件,效果类似于微信朋友圈点开看大图 使用 photoView 实现可点击放大...

    wangxinarhat 评论0 收藏0

发表评论

0条评论

instein

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<