3、安卓数据存储——缓存、内存管理

2、朋友圈里的消息体——SingleMessage的存储:每个消息体用sqlite(各个表项值,图片存本地路径)、消息体里的用户头像、用户上传的图片同时下载后同时存入本地文件、缓存(防止内存溢出):

3、用户消息界面,、上传、修改用户头像的存储:本地文件

缓存的东西,师兄给我介绍了点LRU cache的东西:

当需要在界面上加载一大堆图片的时候,在很多情况下,(比如使用ListView, GridView 或者 ViewPager 这样的组件),屏幕上显示的图片可以通过滑动屏幕等事件不断地增加,最终导致OOM(内存溢出)。

这个时候,使用内存缓存技术可以很好的解决这个问题。内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

这里lrucache这个类定义在了项目中imageLoader这个类中:

public class ImageLoader {  
    /** 
     * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。 
     */  
    private static LruCache<String, Bitmap> mMemoryCache;   
 /** 
     * 获取ImageLoader的实例。 
     *  
     * @return ImageLoader的实例。 
     */  
    public static ImageLoader getInstance() {  
        if (mImageLoader == null) {  
            mImageLoader = new ImageLoader();  
        }  
        return mImageLoader;  
    }  
  
    /** 
     * 将一张图片存储到LruCache中。 
     *  
     * @param key 
     *            LruCache的键,这里传入图片的URL地址。 
     * @param bitmap 
     *            LruCache的键,这里传入从网络上下载的Bitmap对象。 
     */  
    public boolean addBitmapToMemoryCache(String key, Bitmap bitmap) {  
        if (getBitmapFromMemoryCache(key) == null) {  
            mMemoryCache.put(key, bitmap);
            return true;
        }  
        return false;
    }  
  
    /** 
     * 从LruCache中获取一张图片,如果不存在就返回null。 
     *  
     * @param key 
     *            LruCache的键,这里传入图片的URL地址。 
     * @return 对应传入键的Bitmap对象,或者null。 
     */  
    public Bitmap getBitmapFromMemoryCache(String key) {  
        return mMemoryCache.get(key);  
    } 
} 
  

这样在图片下载完成以后,首先获取imageLoader这个实例,然后调用这个类的addBitmapToMemoryCache(String key, Bitmap bitmap)方法,就ok了。然后在需要从缓存中取图片的地方,调用getBitmapFromMemoryCache(String key)就ok了。

相关代码:

dm.downloadImg(imgDownloadUrls, getAppPath() +"/user_pic/"+ users_name +".jpg") ;//图片下载完成后,存入本地文件
 String user_picPath = getAppPath() +"/user_pic/"+users_name+".jpg";  
               File file = new File(user_picPath);
                if(file.exists()){
                  Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource(  
                       getAppPath() +"/user_pic/"+users_name+".jpg", columnWidth_user_pic); 
                if (bitmap != null) {  
                    
                        imageLoader.addBitmapToMemoryCache(imgUrls, bitmap); 
                     
                 //将图片加入缓存,这个方法的key值就是图片的url                 
                    }
   if(imageLoader.getBitmapFromMemoryCache(imageUrl)!= null ){
                Bitmap bitmap = imageLoader.getBitmapFromMemoryCache(imageUrl); //从缓存中取图片
             
                if (bitmap != null && bitmap_head !=null) {  //最好加上判空操作
                     user_pic.setImageBitmap(bitmap);
                    
                     }
                } else {  
                  
                    //缓存中没有,从文件中取图片
                     String user_picPath = getAppPath() +"/user_pic/"+ single_message_username1 +".jpg";  
                       File file = new File(user_picPath);
                       if(file.exists()){
                       int    columnWidth_user_pic   = user_pic.getWidth();
                           Bitmap bitmap1 = ImageLoader.decodeSampledBitmapFromResource(  
                             getAppPath() +"/user_pic/"+single_message_username1 +".jpg", columnWidth_user_pic); 
                      
                        user_pic.setImageBitmap(bitmap1);
                     }  

其实这个缓存本身用起来没什么难度,项目中碰到的问题就是,我们把从服务器下载的大量消息体下载完成后,将用户的图片都加入到了缓存,然后在下拉刷新,用户的手指下滑屏幕的时候,图片的可见性检查问题。首先是加载的时候,将每一个消息体中的图片的url都setTag(),这样往缓存中加载的时候,将url作为key值传进去。然后在下拉刷新那个view里面,对显示在屏幕中间的图片,还有当前图片的前5个、后5个消息体里的图片也从缓存中取出来,并且加载显示到控件上,其他图片都替换成空图(这些消息体的图片显示控件都指向同一个空图),这样缓存的压力就更小了。所以关键就是这个图片可见性检查的问题。

起初,我们尝试用加载热门图片里那样,将每一个图片的顶boderTop、底BoderBottom都setTag(),结果我们这个朋友圈里的tag,由于用户不停刷新,将会更新每一个控件的tag,这样不好操作。后来师兄想到了得到每一个控件的相对于屏幕左上角的绝对纵坐标偏移量,然后当用户的手指离开屏幕后,touchEvent事件里的action

——up,通过handler定时更新用户手指滑动的距离,检查屏幕是否滚动,如果没有滚动,则将绝对纵坐标偏移量出于屏幕分辨率范围内的图片的index取出来,然后将这个index的前、后各5个图片都从缓存中取出来,其余的替换成空图。整个过程都是通过for循环遍历整个friendcircle_list的child来进行图片的可见性检查。