原文出自:方杰|http://fangjie.info/?p=193转载请注明出处

最终效果演示:http://fangjie.sinaapp.com/?page_id=54
该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo

一.ListView的图片异步加载
我们都知道对每一个Weibo Item都有用户头像,而且每一条微博还可能带有图片。如果在加载列表的同时加载图片,这样有几个缺点,第一很费事,界面卡住,用户体验很不好,第二Android在主线程中不能有网络操作,所以本身实现起来就很麻烦。所以我们才实现一个图片异步加载类。继承自AsyncTask<String, Void, Bitmap>,重载其中的方法。doInBackground才是真正的异步操作,做一些耗时的任务,这里就是去服务器上下载图片,onPostExecute是在doInBackground结束后调用的,并传入doInBackground的返回值。

    public AsyncImageLoader(ImageView image, LruCache<String, Bitmap> lruCache,int width,int height) {
        super();
        this.image = image;
        this.lruCache = lruCache;
        this.width=width;
        this.height=width;
    }  

    @Override
    protected Bitmap doInBackground(String... params) {
        Bitmap bitmap = null;
        bitmap = GetUserInfo.getBitmap(params[0]);
        if(width!=0&height!=0)
            bitmap=GetUserInfo.scaleImg(bitmap, width, height);
        addBitmapToMemoryCache(params[0], bitmap);
        return bitmap;
    }  

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        image.setImageBitmap(bitmap);
    }

然后在WeiboAdapter中封装一个接口 loadBitmap,加载图片。

二.ListView图片缓存

ListView经常会上下滑动,而这些图片加载任务就会反复调用,这样就很浪费。可以为图片实现缓存,当某个图片加载过之后需要再次显示只需要从内存中拿出来显示就可以,不需要再去加载。缓存其实有两种缓存,一种是内存缓存,另一种是SD卡缓存,即下载图片到SD卡中。这里我们只讲内存缓存。

结合上面的图片异步加载,整个图片显示的过程是这样:当需要显示图片的时候,先去内存中查找看是否有这种图片的缓存,有的话就直接显示,没有的话,去异步加载,然后保存到内存缓存中,然后显示。

完整的AsyncImageLoader.java代码

package com.fangjie.weibo.util;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

public class AsyncImageLoader extends AsyncTask<String, Void, Bitmap> {

    private ImageView image;
    private LruCache<String, Bitmap> lruCache;
    private int width;
    private int height;
    /**
     * 构造方法,需要把ImageView控件和LruCache 对象传进来
     * @param image 加载图片到此 {@code}ImageView
     * @param lruCache 缓存图片的对象
     */
    public AsyncImageLoader(ImageView image, LruCache<String, Bitmap> lruCache,int width,int height) {
        super();
        this.image = image;
        this.lruCache = lruCache;
        this.width=width;
        this.height=width;
    }  

    @Override
    protected Bitmap doInBackground(String... params) {
        Bitmap bitmap = null;
        bitmap = GetUserInfo.getBitmap(params[0]);
        if(width!=0&height!=0)
            bitmap=GetUserInfo.scaleImg(bitmap, width, height);
        addBitmapToMemoryCache(params[0], bitmap);
        return bitmap;
    }  

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        image.setImageBitmap(bitmap);
    }
        //调用LruCache的put 方法将图片加入内存缓存中,要给这个图片一个key 方便下次从缓存中取出来
    private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemoryCache(key) == null) {
            lruCache.put(key, bitmap);
        }
    }
        //调用Lrucache的get 方法从内存缓存中去图片
    public Bitmap getBitmapFromMemoryCache(String key) {
        return lruCache.get(key);
    }
}

在WeiboAdapter中的调用接口,loadBitmap

    private final int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取当前应用程序所分配的最大内存
    private final int cacheSize = maxMemory / 5;//只分5分之一用来做图片缓存
    private LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(
            cacheSize) {
        protected int sizeOf(String key, Bitmap bitmap) {//复写sizeof()方法
            // replaced by getByteCount() in API 12
            return bitmap.getRowBytes() * bitmap.getHeight() / 1024; //这里是按多少KB来算
        }
    }; 

    /**
     *
     * @param urlStr 所需要加载的图片的url,以String形式传进来,可以把这个url作为缓存图片的key
     * @param image ImageView 控件
     */
    private void loadBitmap(String urlStr, ImageView image,int width,int height) {
        System.out.println(urlStr);
        AsyncImageLoader asyncLoader = new AsyncImageLoader(image, mLruCache,width,height);//什么一个异步图片加载对象
        Bitmap bitmap = asyncLoader.getBitmapFromMemoryCache(urlStr);//首先从内存缓存中获取图片
        if (bitmap != null) {
            image.setImageBitmap(bitmap);//如果缓存中存在这张图片则直接设置给ImageView
        } else {
            image.setImageResource(R.drawable.user_head);//否则先设置成默认的图片
            asyncLoader.execute(urlStr);//然后执行异步任务AsycnTask 去网上加载图片
        }
    }

至此,微博主页的微博列表加载也就全部完成。还有很多细小的点都没讲到,但是都有源码,相信大家都能看得懂的。整个工程文件截图:

代码放在:http://git.oschina.net/fangjie/Sina-Weibo  效果展示:http://fangjie.sinaapp.com/?page_id=54

:由于新浪微博的开发平台申请的应用没有通过审核,所以不是所有的微博帐号都可以授权成功,需要测试的话可以找我,也可以在源码中(com.fangjie.weibo.util.AuthUtil)改成你申请的appkey,appsecret。

微博客户端项目有时间再往下写吧!

Android新浪微博客户端(七)——ListView中的图片异步加载、缓存的更多相关文章

  1. 简单的ListView中item图片异步加载

    前言:     在android开发当中,从目标地址获取图片往往都是采用异步加载的方法.当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来. 这两个区别只是对流的处理不同而已.现 ...

  2. [置顶] Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

  3. Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

  4. Android图片异步加载之Android-Universal-Image-Loader(转)

    今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...

  5. Android ListView 图片异步加载和图片内存缓存

    开发Android应用经常需要处理图片的加载问题.因为图片一般都是存放在服务器端,需要联网去加载,而这又是一个比较耗时的过程,所以Android中都是通过开启一个异步线程去加载.为了增加用户体验,给用 ...

  6. Android图片异步加载框架Android-Universal-Image-Loader

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个 ...

  7. Android 图片异步加载的体会,SoftReference已经不再适用

      在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的 ...

  8. Android图片异步加载

    原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/A ...

  9. imagesLoaded – 检测网页中的图片是否加载

    imagesLoaded 是一个用于来检测网页中的图片是否载入完成的 JavaScript 工具库.支持回调的获取图片加载的进度,还可以绑定自定义事件.可以结合 jQuery.RequireJS 使用 ...

随机推荐

  1. JQ滑动导航菜单的实现

    前言:不多说直接看效果!!! 这样的菜单我们在一般的网站上见到的也比较多,有比较好的用户体验!   原理:这个很重要,任何的特效只要原理搞明白了,实现起来都是很容易的!这个特效的原理很简单,菜单的样式 ...

  2. Linux shell入门基础(四)

    四.进程优先级前台后台 01.进程控制 #find /name aaa & #ps aux | grep find #updatedb &  #ps aux | grep update ...

  3. Oracle中的over(partition by...)分析函数及开窗函数

    假设有一张表student Name  Score  InsertTime   (Name:姓名  Score:成绩 InsertTime:考试时间) 张三     20    2015-08-08 ...

  4. Oracle存储过程及函数

    1.在Oracle中,存储过程包括三部分组成:定义部分.执行部分.和异常处理部分(即例外) eg1:输入员工编号,查询员工的姓名和薪资 create or repalce  procedure myp ...

  5. Qt中绘图坐标QPainter,Viewport与Window的关系

    在Qt中常常要自己重载一些paintEvent函数,这个时候往往忽略了两个很关键的API,那就是setViewport和setWindow. Viewport,顾名思义,反应的是物理坐标,就是你实际想 ...

  6. Mysql 源码编译教程贴

    题外话:这是一篇教程贴,不仅学的是mysql的编译,还是一些编译的知识.我也是一个菜鸟,写一些感悟和心得,有什么问题可以批评指正,谢谢! 如果只是为了安装请移到我的另一篇安装贴: Mysql安装贴 环 ...

  7. 关于一个隐藏和显示物品列表的demo

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  8. 如何使一个你没有源代码的DLL文件变为强命名的DLL

    转载: 有时候你会需要一个DLL是强命名的,比如你想把这个文件放到GAC里面.如果这是一个第三方的DLL,你没有源代码,这会是一件比较麻烦的事情.有一个方法可以解决这个问题. 在VS.NET的命名行窗 ...

  9. Python中函数参数传递问题

    先上两个例子: http://python.jobbole.com/85231/ a = 1 def fun(a): a = 2 fun(a) print a # 结果为1 fun(a)中的a,可以看 ...

  10. Android 数据库读取数据显示 [5]

    2016-12-1 课程内容 昨天学了Android数据库升级.降级.创建 今天把数据库表里面的数据读取出来显示到手机屏幕上 下面代码是MainActivity.java 的代码 package co ...