android 實現相似微信緩存和即時更新好友頭像

引言

使用微信時咱們會發現,首次進入微信的好友列表時,會加載好友頭像,可是再次進入時,就不用從新加載了,並且其餘頁面都不用從新加載,說明微信的好友頭像是緩存在本地的,而後好友修改頭像後,又會及時的更新,這個功能是如何實現的呢,咱們來分析一下數組

分析

關於頭像緩存的實現緩存

頭像是網絡圖片,並且數據量較大,若是用咱們經常使用的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 <T extends View> void display(T container, String uri) {
    display(container, uri, null, null);
}

/**
 * 根據圖片路徑,顯示到具體的View上
 * @param container 要把圖片顯示到的View
 * @param uri 圖片路徑
 * @param displayConfig
 */
public <T extends View> void display(T container, String uri, BitmapDisplayConfig displayConfig) {
    display(container, uri, displayConfig, null);
}

/**
 * 根據圖片路徑,顯示到具體的View上
 * @param container 要把圖片顯示到的View
 * @param uri 圖片路徑
 * @param callBack 加載過程回調各類狀態
 */
public <T extends View> void display(T container, String uri, BitmapLoadCallBack<T> callBack) {
    display(container, uri, null, callBack);
}   
 
 /**
 * 根據圖片路徑,顯示到具體的View上
 * @param container 要把圖片顯示到的View
 * @param uri 圖片路徑
 * @param displayConfig 位圖顯示配置
 * @param callBack
 */
public <T extends View> void display(T container, String uri, BitmapDisplayConfig displayConfig, BitmapLoadCallBack<T> callBack) {
    if (container == null) {
        return;
    }

    if (callBack == null) {
        callBack = new DefaultBitmapLoadCallBack<T>();
    }

    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<T> loadTask = new BitmapLoadTask<T>(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<T>(loadingDrawable, loadTask));

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

從這段代碼中咱們能夠看到,當要加載某張圖片時,會根據圖片地址進行查找是否有對應的bitmap緩存圖片,若是有就直接引用緩存,若是沒有就加載並緩存,因此咱們對圖片的緩存只須要實現以上方法就能夠了,並且只要設置相同的緩存路徑,就能夠實現一個頁面緩存後,其餘頁面有相同圖片也能夠調用。那麼緩存以後,好友更新頭像,又是怎麼作到即時更新的呢?框架

緩存後如何實現即時更新頭像socket

根據查閱的資料,能夠歸結爲如下幾種實現方式:
1.在服務器返回用戶數組時多加一個字段頭像最後一次修改時間或者修改過幾回等標誌符,與緩存進行比較,是否有變化
2.利用圖片的checkSum來實現,若是check到這個數字有變化,就會自動去更新
3.利用socket監聽,當好友頭像更新時候首先會告訴服務器,服務器將變化通知推送到全部好友,好友監聽收到通知後自動更新
第一種方法和第二種方法本質是一致的,經過請求服務器的數據與本地緩存進行對比,是由客戶端處理的,第三種方法的話你換一次頭像就要服務器去提醒你的全部好友一遍,服務器壓力會不會比較大
仔細去研究一下微信,就會發現,當好友頭像修改後,若是你停留在某個頁面,進入的這個頁面是以前進入過的,尚未銷燬,頭像是不會改變的,你須要打開一個新的頁面或者從新進入微信,纔會更新頭像,由此看出,微信並非用的第三種方式,而是採用了前兩種方式的實現原理,只有在建立一個Activity或fragment時,調用接口,讀取服務器數據時纔會更新頭像ide

總結

經過以上的分析,咱們基本捋清了思路,要實現相似微信的緩存和更新還有頭像,先是在磁盤開闢一個空間,用於讀寫頭像的Bitmap,而後建立頁面時,讀取服務器數據和本地緩存進行比較,若是有變化就進行更新this

相關文章
相關標籤/搜索