Android_异步加载2

接着这篇博客写http://blog.csdn.net/two_water/article/details/51477206

        异步加载1这篇博客在最后暴露出了一个问题,就是只在ListView的最后一个Item的ImageView刷新图片,解决问题的方案也提出来了,需要让url和对应的ImageView进行下配对!

ImageLoader的代码把showImageByThread方法里面的判断是否有缓存图片的代码注释了,改到在Adapter那里进行判断,判断是否有缓存图片,如果有显示缓存的图片,如果没有就先显示默认加载的图片,然后再去加载网络图片,并添加缓存!

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.liangdianshui.asynchronouslyload;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.BaseAdapter;  
  9. import android.widget.ImageView;  
  10. import android.widget.TextView;  
  11.   
  12. import java.util.List;  
  13.   
  14. /** 
  15.  * Created by 两点水 on 2016/5/12. 
  16.  */  
  17. public class MyAdapter extends BaseAdapter {  
  18.   
  19.     private Context context;  
  20.     private List<DataBean> list;  
  21.     private ViewHolder mHolder;  
  22.     private ImageLoader mImaeLoader;  
  23.   
  24.     public MyAdapter(Context context, List<DataBean> list) {  
  25.         this.context = context;  
  26.         this.list = list;  
  27.         mImaeLoader = new ImageLoader();  //因为创建了缓存空间,所以放在构造方法,只创建一次  
  28.     }  
  29.   
  30.     @Override  
  31.     public int getCount() {  
  32.         return list.size();  
  33.     }  
  34.   
  35.     @Override  
  36.     public Object getItem(int position) {  
  37.         return list.get(position);  
  38.     }  
  39.   
  40.     @Override  
  41.     public long getItemId(int position) {  
  42.         return position;  
  43.     }  
  44.   
  45.     @Override  
  46.     public View getView(int position, View convertView, ViewGroup parent) {  
  47.         if (convertView == null) {  
  48.             convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, null);  
  49.             mHolder = new ViewHolder();  
  50.             mHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);  
  51.             mHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);  
  52.             mHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);  
  53.             convertView.setTag(mHolder);  
  54.         } else {  
  55.             mHolder = (ViewHolder) convertView.getTag();  
  56.         }  
  57. //      mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片  
  58.         String url = list.get(position).getDataIconUrl();  
  59.         mHolder.ivIcon.setTag(url);//为防止listview显示的图片错乱,重复,闪烁  
  60. //      new ImageLoader().showImageByThread(mHolder.ivIcon, url);  
  61.         Bitmap bitmapFromCache = mImaeLoader.getBitmapFromCache(url);  
  62.         if (bitmapFromCache != null) {  
  63.             mHolder.ivIcon.setImageBitmap(bitmapFromCache);  
  64.         }else{  
  65.             mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);  
  66.             mImaeLoader.showImageByThread(mHolder.ivIcon, url);  
  67.         }  
  68.         mHolder.tvTitle.setText(list.get(position).getDataTitle());  
  69.         mHolder.tvContent.setText(list.get(position).getDataContent());  
  70.         return convertView;  
  71.     }  
  72.   
  73.     class ViewHolder {  
  74.         private TextView tvTitle;  
  75.         private TextView tvContent;  
  76.         private ImageView ivIcon;  
  77.     }  
  78. }  

ImageLoader的代码:

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.liangdianshui.asynchronouslyload;  
  2.   
  3. import android.graphics.Bitmap;  
  4. import android.graphics.BitmapFactory;  
  5. import android.os.Handler;  
  6. import android.os.Message;  
  7. import android.util.LruCache;  
  8. import android.widget.ImageView;  
  9.   
  10. import java.io.BufferedInputStream;  
  11. import java.io.IOException;  
  12. import java.io.InputStream;  
  13. import java.net.HttpURLConnection;  
  14. import java.net.MalformedURLException;  
  15. import java.net.URL;  
  16.   
  17. /** 
  18.  * Created by 两点水 on 2016/5/22. 
  19.  */  
  20. public class ImageLoader {  
  21.   
  22.     private ImageView mImageView;  
  23.     private String mUrl;  
  24.     private final int URL_BITMAP = 0;  
  25.     private LruCache<String, Bitmap> mCache;   //使用Lru缓存(使用的Lru算法:近期最少使用算法)  
  26.   
  27.     /** 
  28.      * 使用缓存肯定要先声明缓存空间,因此在构造方法中声明缓存空间 
  29.      */  
  30.     public ImageLoader() {  
  31.         //获取程序最大使用的内存  
  32.         int maxMemory = (int) Runtime.getRuntime().maxMemory();  
  33.         int cacheSize = maxMemory / 4;  //缓存大小为最大缓存的四分之一  
  34.         //创建缓存,把缓存大小传进去  
  35.         mCache = new LruCache<String, Bitmap>(cacheSize) {  
  36.             @Override  
  37.             protected int sizeOf(String key, Bitmap value) {  
  38.                 //每次存入缓存的时候都会调用这个方法,因此我们把图片的大小放进去  
  39.                 return value.getByteCount();  
  40.             }  
  41.         };  
  42.     }  
  43.   
  44.     /** 
  45.      * 把图片加入到缓存 
  46.      * 
  47.      * @param url 
  48.      * @param bitmap 
  49.      */  
  50.     public void addBitmapToCache(String url, Bitmap bitmap) {  
  51.         //LruCache好比是一个map,采用键值对的形式去保存图片  
  52.         if (getBitmapFromCache(url) == null) {  
  53.             //如果缓存中没有这个Bitmap,就把bitmap放进缓存  
  54.             mCache.put(url, bitmap);  
  55.         }  
  56.     }  
  57.   
  58.     /** 
  59.      * 从缓存中获取图片 
  60.      * 
  61.      * @param url 
  62.      */  
  63.     public Bitmap getBitmapFromCache(String url) {  
  64.         return mCache.get(url); //根据url获取图片  
  65.     }  
  66.   
  67.     Handler mHandler = new Handler() {  
  68.   
  69.         @Override  
  70.         public void handleMessage(Message msg) {  
  71.             super.handleMessage(msg);  
  72.             switch (msg.what) {  
  73.                 case URL_BITMAP:  
  74. //                  if (mImageView.getTag().equals(mUrl)) {  
  75. //                      mImageView.setImageBitmap((Bitmap) msg.obj);  
  76. //                  }  
  77.                     //因为传过来的对象更改了,这里也要跟着更改  
  78.                     ImgHolder holder = (ImgHolder) msg.obj;  
  79.                     if (holder.imageView.getTag().equals(holder.url)) {  
  80.                         holder.imageView.setImageBitmap(holder.bitmap);  
  81.                     }  
  82.                     break;  
  83.             }  
  84.         }  
  85.     };  
  86.   
  87.   
  88.     /** 
  89.      * 多线程加载图片(Thread+Handler) 
  90.      * 根据url获取的itmap显示在ImageView中 
  91.      * 
  92.      * @param imageView 
  93.      * @param url 
  94.      */  
  95.     public void showImageByThread(final ImageView imageView, final String url) {  
  96.         mImageView = imageView;  
  97.         mUrl = url;  
  98.   
  99.         //从缓存中取出图片  
  100. //      Bitmap bitmap = getBitmapFromCache(url);  
  101.         //判断缓存中是否含有这张图片,没有的话去网络下载图片  
  102. //      if (bitmap == null) {  
  103.             new Thread(new Runnable() {  
  104.                 @Override  
  105.                 public void run() {  
  106.                     Bitmap bitmap = getBitmapFromURL(url);  
  107.                     //把下载下来的图片加到缓存中  
  108.                     if (bitmap != null) {  
  109.                         addBitmapToCache(url, bitmap);  
  110.                     }  
  111.                     Message message = new Message();  
  112. //                  message.obj = bitmap;  
  113.                     //为了保证ImageView与这时候传递过来的图像一一对应的关系  
  114.                     message.obj = new ImgHolder(imageView, bitmap, url);  
  115.                     message.what = URL_BITMAP;  
  116.                     mHandler.sendMessage(message);  
  117.                 }  
  118.             }).start();  //记得start();  
  119. //      } else {  
  120. //          Message message = new Message();  
  121. //          message.obj = bitmap;  
  122.             //为了保证ImageView与这时候传递过来的图像一一对应的关系  
  123. //          message.obj = new ImgHolder(imageView, bitmap, url);  
  124. //          message.what = URL_BITMAP;  
  125. //          mHandler.sendMessage(message);  
  126. //      }  
  127.     }  
  128.   
  129.     /** 
  130.      * 根据rul获取bitmap 
  131.      * 
  132.      * @param url 
  133.      * @return 
  134.      */  
  135.   
  136.     private Bitmap getBitmapFromURL(String url) {  
  137.         InputStream inputStream = null;  
  138.         try {  
  139.             URL urlBitmap = new URL(url);  
  140.             HttpURLConnection urlConnection = (HttpURLConnection) urlBitmap.openConnection();  
  141.             inputStream = new BufferedInputStream(urlConnection.getInputStream());  
  142.             Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
  143.             Thread.sleep(1000); //模拟网速慢的情况,为了更好的显示ImageView刷新多次的情况  
  144.             urlConnection.disconnect(); //关闭http连接  
  145.             return bitmap;  
  146.         } catch (MalformedURLException e) {  
  147.             e.printStackTrace();  
  148.         } catch (IOException e) {  
  149.             e.printStackTrace();  
  150.         } catch (InterruptedException e) {  
  151.             e.printStackTrace();  
  152.         } finally {  
  153.             try {  
  154.                 inputStream.close(); //关闭流  
  155.             } catch (IOException e) {  
  156.                 e.printStackTrace();  
  157.             }  
  158.         }  
  159.         return null;  
  160.     }  
  161.   
  162.     /** 
  163.      * 新建一个类,记录ImageView,bitmap和url 
  164.      */  
  165.     private class ImgHolder {  
  166.         public Bitmap bitmap;  
  167.         public ImageView imageView;  
  168.         public String url;  
  169.   
  170.         public ImgHolder(ImageView iv, Bitmap bm, String url) {  
  171.             this.imageView = iv;  
  172.             this.bitmap = bm;  
  173.             this.url = url;  
  174.         }  
  175.     }  
  176.   
  177.   
  178. }  

效果图:

 

 

 

        使用AsyncTask实现上面的效果,其实AsyncTask也是根据多线程来实现的,因此基本的实现方式是一样的,直接贴代码:

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.liangdianshui.asynchronouslyload;  
  2.   
  3. import android.graphics.Bitmap;  
  4. import android.graphics.BitmapFactory;  
  5. import android.os.AsyncTask;  
  6. import android.os.Handler;  
  7. import android.os.Message;  
  8. import android.util.LruCache;  
  9. import android.widget.ImageView;  
  10.   
  11. import java.io.BufferedInputStream;  
  12. import java.io.IOException;  
  13. import java.io.InputStream;  
  14. import java.net.HttpURLConnection;  
  15. import java.net.MalformedURLException;  
  16. import java.net.URL;  
  17.   
  18. /** 
  19.  * Created by 两点水 on 2016/5/22. 
  20.  */  
  21. public class ImageLoader {  
  22.   
  23.     private ImageView mImageView;  
  24.     private String mUrl;  
  25.     private final int URL_BITMAP = 0;  
  26.     private LruCache<String, Bitmap> mCache;   //使用Lru缓存(使用的Lru算法:近期最少使用算法)  
  27.   
  28.     /** 
  29.      * 使用缓存肯定要先声明缓存空间,因此在构造方法中声明缓存空间 
  30.      */  
  31.     public ImageLoader() {  
  32.         //获取程序最大使用的内存  
  33.         int maxMemory = (int) Runtime.getRuntime().maxMemory();  
  34.         int cacheSize = maxMemory / 4;  //缓存大小为最大缓存的四分之一  
  35.         //创建缓存,把缓存大小传进去  
  36.         mCache = new LruCache<String, Bitmap>(cacheSize) {  
  37.             @Override  
  38.             protected int sizeOf(String key, Bitmap value) {  
  39.                 //每次存入缓存的时候都会调用这个方法,因此我们把图片的大小放进去  
  40.                 return value.getByteCount();  
  41.             }  
  42.         };  
  43.     }  
  44.   
  45.     /** 
  46.      * 把图片加入到缓存 
  47.      * 
  48.      * @param url 
  49.      * @param bitmap 
  50.      */  
  51.     public void addBitmapToCache(String url, Bitmap bitmap) {  
  52.         //LruCache好比是一个map,采用键值对的形式去保存图片  
  53.         if (getBitmapFromCache(url) == null) {  
  54.             //如果缓存中没有这个Bitmap,就把bitmap放进缓存  
  55.             mCache.put(url, bitmap);  
  56.         }  
  57.     }  
  58.   
  59.     /** 
  60.      * 从缓存中获取图片 
  61.      * 
  62.      * @param url 
  63.      */  
  64.     public Bitmap getBitmapFromCache(String url) {  
  65.         return mCache.get(url); //根据url获取图片  
  66.     }  
  67.   
  68.     Handler mHandler = new Handler() {  
  69.   
  70.         @Override  
  71.         public void handleMessage(Message msg) {  
  72.             super.handleMessage(msg);  
  73.             switch (msg.what) {  
  74.                 case URL_BITMAP:  
  75. //                  if (mImageView.getTag().equals(mUrl)) {  
  76. //                      mImageView.setImageBitmap((Bitmap) msg.obj);  
  77. //                  }  
  78.                     //因为传过来的对象更改了,这里也要跟着更改  
  79.                     ImgHolder holder = (ImgHolder) msg.obj;  
  80.                     if (holder.imageView.getTag().equals(holder.url)) {  
  81.                         holder.imageView.setImageBitmap(holder.bitmap);  
  82.                     }  
  83.                     break;  
  84.             }  
  85.         }  
  86.     };  
  87.   
  88.   
  89.     /** 
  90.      * 多线程加载图片(Thread+Handler) 
  91.      * 根据url获取的itmap显示在ImageView中 
  92.      * 
  93.      * @param imageView 
  94.      * @param url 
  95.      */  
  96.     public void showImageByThread(final ImageView imageView, final String url) {  
  97.         mImageView = imageView;  
  98.         mUrl = url;  
  99.   
  100.         //从缓存中取出图片  
  101. //      Bitmap bitmap = getBitmapFromCache(url);  
  102.         //判断缓存中是否含有这张图片,没有的话去网络下载图片  
  103. //      if (bitmap == null) {  
  104.         new Thread(new Runnable() {  
  105.             @Override  
  106.             public void run() {  
  107.                 Bitmap bitmap = getBitmapFromURL(url);  
  108.                 //把下载下来的图片加到缓存中  
  109.                 if (bitmap != null) {  
  110.                     addBitmapToCache(url, bitmap);  
  111.                 }  
  112.                 Message message = new Message();  
  113. //                  message.obj = bitmap;  
  114.                 //为了保证ImageView与这时候传递过来的图像一一对应的关系  
  115.                 message.obj = new ImgHolder(imageView, bitmap, url);  
  116.                 message.what = URL_BITMAP;  
  117.                 mHandler.sendMessage(message);  
  118.             }  
  119.         }).start();  //记得start();  
  120. //      } else {  
  121. //          Message message = new Message();  
  122. //          message.obj = bitmap;  
  123.         //为了保证ImageView与这时候传递过来的图像一一对应的关系  
  124. //          message.obj = new ImgHolder(imageView, bitmap, url);  
  125. //          message.what = URL_BITMAP;  
  126. //          mHandler.sendMessage(message);  
  127. //      }  
  128.     }  
  129.   
  130.     /** 
  131.      * 根据rul获取bitmap 
  132.      * 
  133.      * @param url 
  134.      * @return 
  135.      */  
  136.   
  137.     private Bitmap getBitmapFromURL(String url) {  
  138.         InputStream inputStream = null;  
  139.         try {  
  140.             URL urlBitmap = new URL(url);  
  141.             HttpURLConnection urlConnection = (HttpURLConnection) urlBitmap.openConnection();  
  142.             inputStream = new BufferedInputStream(urlConnection.getInputStream());  
  143.             Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
  144. //          Thread.sleep(1000); //模拟网速慢的情况,为了更好的显示ImageView刷新多次的情况  
  145.             urlConnection.disconnect(); //关闭http连接  
  146.             return bitmap;  
  147.         } catch (MalformedURLException e) {  
  148.             e.printStackTrace();  
  149.         } catch (IOException e) {  
  150.             e.printStackTrace();  
  151.         } finally {  
  152.             try {  
  153.                 inputStream.close(); //关闭流  
  154.             } catch (IOException e) {  
  155.                 e.printStackTrace();  
  156.             }  
  157.         }  
  158.         return null;  
  159.     }  
  160.   
  161.     /** 
  162.      * 新建一个类,记录ImageView,bitmap和url 
  163.      */  
  164.     private class ImgHolder {  
  165.         public Bitmap bitmap;  
  166.         public ImageView imageView;  
  167.         public String url;  
  168.   
  169.         public ImgHolder(ImageView iv, Bitmap bm, String url) {  
  170.             this.imageView = iv;  
  171.             this.bitmap = bm;  
  172.             this.url = url;  
  173.         }  
  174.     }  
  175.   
  176.   
  177.     /** 
  178.      * 通过AsyncTask异步加载图片显示到ImageView 
  179.      * 
  180.      * @param imageView 
  181.      * @param url 
  182.      */  
  183.     public void showImageByAsyncTask(ImageView imageView, String url) {  
  184.         Bitmap bitmap = getBitmapFromCache(url);  
  185.         if (bitmap == null) {  //判断缓存是否有对应的图片  
  186.             new MyAsyncTask(imageView, url).execute(url);  
  187.         } else {  
  188.             imageView.setImageBitmap(bitmap);  
  189.         }  
  190.     }  
  191.   
  192.     /** 
  193.      * 创建MyAsyncTask内部类 
  194.      * 通过AsyncTask异步加载图片 
  195.      */  
  196.     private class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {  
  197.   
  198.         private ImageView mImageView;  
  199.         private String mUrl;  
  200.   
  201.         /** 
  202.          * 创建构造方法初始化ImagaeView 
  203.          */  
  204.         public MyAsyncTask(ImageView imageView, String url) {  
  205.             mImageView = imageView;  
  206.             mUrl = url;  
  207.         }  
  208.   
  209.         @Override  
  210.         protected void onPreExecute() {  
  211.             super.onPreExecute();  
  212.         }  
  213.   
  214.         @Override  
  215.         protected Bitmap doInBackground(String... params) {  
  216.             String url = params[0];  
  217.             Bitmap bitmap = getBitmapFromURL(url);  
  218.             if (bitmap != null) {  
  219.                 addBitmapToCache(url, bitmap); //增叫图片到缓存  
  220.             }  
  221.             return bitmap;  
  222.         }  
  223.   
  224.         @Override  
  225.         protected void onPostExecute(Bitmap bitmap) {  
  226.             super.onPostExecute(bitmap);  
  227.             if (mImageView.getTag().equals(mUrl)) {  
  228.                 mImageView.setImageBitmap(bitmap);  
  229.             }  
  230.         }  
  231.     }  
  232.   
  233. }  

Adapter的代码:

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.liangdianshui.asynchronouslyload;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.BaseAdapter;  
  9. import android.widget.ImageView;  
  10. import android.widget.TextView;  
  11.   
  12. import java.util.List;  
  13.   
  14. /** 
  15.  * Created by 两点水 on 2016/5/12. 
  16.  */  
  17. public class MyAdapter extends BaseAdapter {  
  18.   
  19.     private Context context;  
  20.     private List<DataBean> list;  
  21.     private ViewHolder mHolder;  
  22.     private ImageLoader mImaeLoader;  
  23.   
  24.     public MyAdapter(Context context, List<DataBean> list) {  
  25.         this.context = context;  
  26.         this.list = list;  
  27.         mImaeLoader = new ImageLoader();  //因为创建了缓存空间,所以放在构造方法,只创建一次  
  28.     }  
  29.   
  30.     @Override  
  31.     public int getCount() {  
  32.         return list.size();  
  33.     }  
  34.   
  35.     @Override  
  36.     public Object getItem(int position) {  
  37.         return list.get(position);  
  38.     }  
  39.   
  40.     @Override  
  41.     public long getItemId(int position) {  
  42.         return position;  
  43.     }  
  44.   
  45.     @Override  
  46.     public View getView(int position, View convertView, ViewGroup parent) {  
  47.         if (convertView == null) {  
  48.             convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, null);  
  49.             mHolder = new ViewHolder();  
  50.             mHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);  
  51.             mHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);  
  52.             mHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);  
  53.             convertView.setTag(mHolder);  
  54.         } else {  
  55.             mHolder = (ViewHolder) convertView.getTag();  
  56.         }  
  57. //      mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片  
  58.         String url = list.get(position).getDataIconUrl();  
  59.         mHolder.ivIcon.setTag(url);//为防止listview显示的图片错乱,重复,闪烁  
  60. //      new ImageLoader().showImageByThread(mHolder.ivIcon, url);  
  61.         /** 
  62.          * 注释多线程异步加载图片的代码 
  63.          */  
  64. //      Bitmap bitmapFromCache = mImaeLoader.getBitmapFromCache(url);  
  65. //      if (bitmapFromCache != null) {  
  66. //          mHolder.ivIcon.setImageBitmap(bitmapFromCache);  
  67. //      } else {  
  68. //          mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);  
  69. //          mImaeLoader.showImageByThread(mHolder.ivIcon, url);  
  70. //      }  
  71.   
  72.         /** 
  73.          *使用AsyncTask的方式实现多线程 
  74.          */  
  75.         mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片  
  76.         mImaeLoader.showImageByAsyncTask(mHolder.ivIcon, url);  
  77.   
  78.         mHolder.tvTitle.setText(list.get(position).getDataTitle());  
  79.         mHolder.tvContent.setText(list.get(position).getDataContent());  
  80.         return convertView;  
  81.     }  
  82.   
  83.     class ViewHolder {  
  84.         private TextView tvTitle;  
  85.         private TextView tvContent;  
  86.         private ImageView ivIcon;  
  87.     }  
  88. }  

 

       效果图跟上面多线程实现的效果图是一样的!
ListView滚动时的高效优化:
           为什么要进行ListView滚动时的优化呢?当Item的界面很复杂的时候,我们的做法是一边滚动时还在加载图片的,加载完成后在主线程中更新ImageView,如果刚好在滚动的时候,更新ImageVIew,因为都是在主线程工作,这时候可能会有卡顿的现象!
       为了解决这种卡顿的现象,我们可以在用户滚动ListView的时候不更新ImageVeiw,只有当用户停止滚动的时候才更新,这样就不卡顿了!
       因此Adapter首先要监听滑动事件,在第一次加载的时候进行加载更新可见项item的视图,之后都是在ListView滑动停止的时候才更新加载图片,其余情况不加载图片!

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.liangdianshui.asynchronouslyload;  
  2.   
  3. import android.content.Context;  
  4. import android.view.LayoutInflater;  
  5. import android.view.View;  
  6. import android.view.ViewGroup;  
  7. import android.widget.AbsListView;  
  8. import android.widget.BaseAdapter;  
  9. import android.widget.ImageView;  
  10. import android.widget.ListView;  
  11. import android.widget.TextView;  
  12.   
  13. import java.util.List;  
  14.   
  15. /** 
  16.  * Created by 两点水 on 2016/5/12. 
  17.  */  
  18. public class MyAdapter extends BaseAdapter implements AbsListView.OnScrollListener {  
  19.   
  20.     private Context context;  
  21.     private List<DataBean> list;  
  22.     private ViewHolder mHolder;  
  23.     private ImageLoader mImaeLoader;  
  24.     private int mStart, mEnd;//当前可见项的起始位置  
  25.     public static String URLS[];//用于保存所有的图片URL地址  
  26.     private boolean mFirstIn;//用于判断是否首次启动预加载  
  27.   
  28.     public MyAdapter(Context context, List<DataBean> list, ListView listView) {  
  29.         this.context = context;  
  30.         this.list = list;  
  31.         mFirstIn = true;  
  32.         mImaeLoader = new ImageLoader(listView);  //因为创建了缓存空间,所以放在构造方法,只创建一次  
  33.         //保存所有的图片URL地址  
  34.         URLS = new String[list.size()];  
  35.         for (int i = 0; i < URLS.length; i++) {  
  36.             URLS[i] = list.get(i).getDataIconUrl();  
  37.         }  
  38.         //实现listview滑动监听接口  
  39.         listView.setOnScrollListener(this);  
  40.     }  
  41.   
  42.     @Override  
  43.     public int getCount() {  
  44.         return list.size();  
  45.     }  
  46.   
  47.     @Override  
  48.     public Object getItem(int position) {  
  49.         return list.get(position);  
  50.     }  
  51.   
  52.     @Override  
  53.     public long getItemId(int position) {  
  54.         return position;  
  55.     }  
  56.   
  57.     @Override  
  58.     public View getView(int position, View convertView, ViewGroup parent) {  
  59.         if (convertView == null) {  
  60.             convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, null);  
  61.             mHolder = new ViewHolder();  
  62.             mHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);  
  63.             mHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);  
  64.             mHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);  
  65.             convertView.setTag(mHolder);  
  66.         } else {  
  67.             mHolder = (ViewHolder) convertView.getTag();  
  68.         }  
  69. //      mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片  
  70.         String url = list.get(position).getDataIconUrl();  
  71.         mHolder.ivIcon.setTag(url);//为防止listview显示的图片错乱,重复,闪烁  
  72.   
  73. //      new ImageLoader().showImageByThread(mHolder.ivIcon, url);  
  74.         /** 
  75.          * 多线程异步加载图片 
  76.          */  
  77. //      Bitmap bitmapFromCache = mImaeLoader.getBitmapFromCache(url);  
  78. //      if (bitmapFromCache != null) {  
  79. //          mHolder.ivIcon.setImageBitmap(bitmapFromCache);  
  80. //      } else {  
  81. //          mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);  
  82. //          mImaeLoader.showImageByThread(mHolder.ivIcon, url);  
  83. //      }  
  84.   
  85.         /** 
  86.          *使用AsyncTask的方式实现多线程 
  87.          */  
  88. //        mHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//默认加载的图片  
  89.         mImaeLoader.showImageByAsyncTask(mHolder.ivIcon, url);  
  90.         mHolder.tvTitle.setText(list.get(position).getDataTitle());  
  91.         mHolder.tvContent.setText(list.get(position).getDataContent());  
  92.         return convertView;  
  93.     }  
  94.   
  95.     @Override  
  96.     public void onScrollStateChanged(AbsListView view, int scrollState) {  
  97.         //滚动状态为停止时,加载当前可见的数据项  
  98.         if (scrollState == SCROLL_STATE_IDLE) {  
  99.             mImaeLoader.loadPartImageView(mStart, mEnd);  
  100.         } else {//滑动没有停止时,停止任务  
  101.             mImaeLoader.CancelAllTask();  
  102.         }  
  103.     }  
  104.   
  105.     @Override  
  106.     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {  
  107.         mStart = firstVisibleItem;  
  108.         mEnd = firstVisibleItem + visibleItemCount;  
  109.         //首次启动预加载  
  110.         if (mFirstIn && visibleItemCount > 0) {  
  111.             mImaeLoader.loadPartImageView(mStart, mEnd);  
  112.             mFirstIn = false;  
  113.         }  
  114.     }  
  115.   
  116.     class ViewHolder {  
  117.         private TextView tvTitle;  
  118.         private TextView tvContent;  
  119.         private ImageView ivIcon;  
  120.     }  
  121. }  

ImageLoader中写一个加载可见项视图Item的方法,然后修改下异步加载图片的方法:

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.liangdianshui.asynchronouslyload;  
  2.   
  3. import android.graphics.Bitmap;  
  4. import android.graphics.BitmapFactory;  
  5. import android.os.AsyncTask;  
  6. import android.os.Handler;  
  7. import android.os.Message;  
  8. import android.util.LruCache;  
  9. import android.widget.ImageView;  
  10. import android.widget.ListView;  
  11.   
  12. import java.io.BufferedInputStream;  
  13. import java.io.IOException;  
  14. import java.io.InputStream;  
  15. import java.net.HttpURLConnection;  
  16. import java.net.MalformedURLException;  
  17. import java.net.URL;  
  18. import java.util.HashSet;  
  19. import java.util.Set;  
  20.   
  21. /** 
  22.  * Created by 两点水 on 2016/5/22. 
  23.  */  
  24. public class ImageLoader {  
  25.   
  26.     private ImageView mImageView;  
  27.     private String mUrl;  
  28.     private final int URL_BITMAP = 0;  
  29.     private LruCache<String, Bitmap> mCache;   //使用Lru缓存(使用的Lru算法:近期最少使用算法)  
  30.     private ListView mlistView;  
  31.     private Set<MyAsyncTask> mTasks;  
  32.   
  33.     /** 
  34.      * 使用缓存肯定要先声明缓存空间,因此在构造方法中声明缓存空间 
  35.      */  
  36.     public ImageLoader(ListView listView) {  
  37.         this.mlistView = listView;  
  38.         mTasks = new HashSet<>();  
  39.         //获取程序最大使用的内存  
  40.         int maxMemory = (int) Runtime.getRuntime().maxMemory();  
  41.         int cacheSize = maxMemory / 4;  //缓存大小为最大缓存的四分之一  
  42.         //创建缓存,把缓存大小传进去  
  43.         mCache = new LruCache<String, Bitmap>(cacheSize) {  
  44.             @Override  
  45.             protected int sizeOf(String key, Bitmap value) {  
  46.                 //每次存入缓存的时候都会调用这个方法,因此我们把图片的大小放进去  
  47.                 return value.getByteCount();  
  48.             }  
  49.         };  
  50.     }  
  51.   
  52.     /** 
  53.      * 把图片加入到缓存 
  54.      * 
  55.      * @param url 
  56.      * @param bitmap 
  57.      */  
  58.     public void addBitmapToCache(String url, Bitmap bitmap) {  
  59.         //LruCache好比是一个map,采用键值对的形式去保存图片  
  60.         if (getBitmapFromCache(url) == null) {  
  61.             //如果缓存中没有这个Bitmap,就把bitmap放进缓存  
  62.             mCache.put(url, bitmap);  
  63.         }  
  64.     }  
  65.   
  66.     /** 
  67.      * 从缓存中获取图片 
  68.      * 
  69.      * @param url 
  70.      */  
  71.     public Bitmap getBitmapFromCache(String url) {  
  72.         return mCache.get(url); //根据url获取图片  
  73.     }  
  74.   
  75.     Handler mHandler = new Handler() {  
  76.   
  77.         @Override  
  78.         public void handleMessage(Message msg) {  
  79.             super.handleMessage(msg);  
  80.             switch (msg.what) {  
  81.                 case URL_BITMAP:  
  82. //                  if (mImageView.getTag().equals(mUrl)) {  
  83. //                      mImageView.setImageBitmap((Bitmap) msg.obj);  
  84. //                  }  
  85.                     //因为传过来的对象更改了,这里也要跟着更改  
  86.                     ImgHolder holder = (ImgHolder) msg.obj;  
  87.                     if (holder.imageView.getTag().equals(holder.url)) {  
  88.                         holder.imageView.setImageBitmap(holder.bitmap);  
  89.                     }  
  90.                     break;  
  91.             }  
  92.         }  
  93.     };  
  94.   
  95.   
  96.     /** 
  97.      * 多线程加载图片(Thread+Handler) 
  98.      * 根据url获取的itmap显示在ImageView中 
  99.      * 
  100.      * @param imageView 
  101.      * @param url 
  102.      */  
  103.     public void showImageByThread(final ImageView imageView, final String url) {  
  104.         mImageView = imageView;  
  105.         mUrl = url;  
  106.   
  107.         //从缓存中取出图片  
  108. //      Bitmap bitmap = getBitmapFromCache(url);  
  109.         //判断缓存中是否含有这张图片,没有的话去网络下载图片  
  110. //      if (bitmap == null) {  
  111.         new Thread(new Runnable() {  
  112.             @Override  
  113.             public void run() {  
  114.                 Bitmap bitmap = getBitmapFromURL(url);  
  115.                 //把下载下来的图片加到缓存中  
  116.                 if (bitmap != null) {  
  117.                     addBitmapToCache(url, bitmap);  
  118.                 }  
  119.                 Message message = new Message();  
  120. //                  message.obj = bitmap;  
  121.                 //为了保证ImageView与这时候传递过来的图像一一对应的关系  
  122.                 message.obj = new ImgHolder(imageView, bitmap, url);  
  123.                 message.what = URL_BITMAP;  
  124.                 mHandler.sendMessage(message);  
  125.             }  
  126.         }).start();  //记得start();  
  127. //      } else {  
  128. //          Message message = new Message();  
  129. //          message.obj = bitmap;  
  130.         //为了保证ImageView与这时候传递过来的图像一一对应的关系  
  131. //          message.obj = new ImgHolder(imageView, bitmap, url);  
  132. //          message.what = URL_BITMAP;  
  133. //          mHandler.sendMessage(message);  
  134. //      }  
  135.     }  
  136.   
  137.     /** 
  138.      * 根据rul获取bitmap 
  139.      * 
  140.      * @param url 
  141.      * @return 
  142.      */  
  143.     private Bitmap getBitmapFromURL(String url) {  
  144.         InputStream inputStream = null;  
  145.         try {  
  146.             URL urlBitmap = new URL(url);  
  147.             HttpURLConnection urlConnection = (HttpURLConnection) urlBitmap.openConnection();  
  148.             inputStream = new BufferedInputStream(urlConnection.getInputStream());  
  149.             Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
  150. //          Thread.sleep(1000); //模拟网速慢的情况,为了更好的显示ImageView刷新多次的情况  
  151.             urlConnection.disconnect(); //关闭http连接  
  152.             return bitmap;  
  153.         } catch (MalformedURLException e) {  
  154.             e.printStackTrace();  
  155.         } catch (IOException e) {  
  156.             e.printStackTrace();  
  157.         } finally {  
  158.             try {  
  159.                 inputStream.close(); //关闭流  
  160.             } catch (IOException e) {  
  161.                 e.printStackTrace();  
  162.             }  
  163.         }  
  164.         return null;  
  165.     }  
  166.   
  167.     /** 
  168.      * 新建一个类,记录ImageView,bitmap和url 
  169.      */  
  170.     private class ImgHolder {  
  171.         public Bitmap bitmap;  
  172.         public ImageView imageView;  
  173.         public String url;  
  174.   
  175.         public ImgHolder(ImageView iv, Bitmap bm, String url) {  
  176.             this.imageView = iv;  
  177.             this.bitmap = bm;  
  178.             this.url = url;  
  179.         }  
  180.     }  
  181.   
  182.   
  183.     /** 
  184.      * 通过AsyncTask异步加载图片显示到ImageView 
  185.      * 
  186.      * @param imageView 
  187.      * @param url 
  188.      */  
  189.     public void showImageByAsyncTask(ImageView imageView, String url) {  
  190.         Bitmap bitmap = getBitmapFromCache(url);  
  191.         if (bitmap == null) {  //判断缓存是否有对应的图片  
  192. //            new MyAsyncTask(imageView, url).execute(url);  
  193.             imageView.setImageResource(R.mipmap.ic_launcher);  
  194.         } else {  
  195.             imageView.setImageBitmap(bitmap);  
  196.         }  
  197.     }  
  198.   
  199.     /** 
  200.      * 创建MyAsyncTask内部类 
  201.      * 通过AsyncTask异步加载图片 
  202.      */  
  203.     private class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {  
  204.   
  205.         private ImageView mImageView;  
  206.         private String mUrl;  
  207.   
  208.         /** 
  209.          * 创建构造方法初始化ImagaeView 
  210.          */  
  211.         public MyAsyncTask(ImageView imageView, String url) {  
  212.             mImageView = imageView;  
  213.             mUrl = url;  
  214.         }  
  215.   
  216.         public MyAsyncTask(String url) {  
  217.             mUrl = url;  
  218.         }  
  219.   
  220.   
  221.         @Override  
  222.         protected void onPreExecute() {  
  223.             super.onPreExecute();  
  224.         }  
  225.   
  226.         @Override  
  227.         protected Bitmap doInBackground(String... params) {  
  228.             String url = params[0];  
  229.             Bitmap bitmap = getBitmapFromURL(url);  
  230.             if (bitmap != null) {  
  231.                 addBitmapToCache(url, bitmap); //增叫图片到缓存  
  232.             }  
  233.             return bitmap;  
  234.         }  
  235.   
  236.         @Override  
  237.         protected void onPostExecute(Bitmap bitmap) {  
  238.             super.onPostExecute(bitmap);  
  239. //            if (mImageView.getTag().equals(mUrl)) {  
  240. //                mImageView.setImageBitmap(bitmap);  
  241. //            }  
  242.             //从ListView中获取Imageview  
  243.             ImageView imageView = (ImageView) mlistView.findViewWithTag(mUrl);  
  244.             if (imageView != null && bitmap != null) {  
  245.                 imageView.setImageBitmap(bitmap);  
  246.             }  
  247.         }  
  248.     }  
  249.   
  250.     /** 
  251.      * 加载部分可见的图片 
  252.      */  
  253.     public void loadPartImageView(int start, int end) {  
  254.         for (int i = start; i < end; i++) {  
  255.             String url = MyAdapter.URLS[i];//得到可见项目起始中的各个url  
  256.             //得到缓存中的Bitmap  
  257.             Bitmap bitmap = getBitmapFromCache(url);  
  258.             //bitmap为空就下载,非空就直接使用  
  259.             if (bitmap == null) {  
  260.                 MyAsyncTask task = new MyAsyncTask(url);  
  261.                 task.execute(url);  
  262.                 mTasks.add(task);  
  263.             } else {  
  264.                 //从ListView中获取Imageview  
  265.                 ImageView imageView = (ImageView) mlistView.findViewWithTag(url);  
  266.                 imageView.setImageBitmap(bitmap);  
  267.             }  
  268.         }  
  269.     }  
  270.   
  271.     /** 
  272.      * 取消当前正在运行的所有任务 
  273.      */  
  274.     public void CancelAllTask() {  
  275.         if (mTasks != null) {  
  276.             for (MyAsyncTask task :  
  277.                     mTasks) {  
  278.                 task.cancel(true);  
  279.             }  
  280.         }  
  281.     }  
  282.   
  283. }  

Demo地址:http://download.csdn.net/detail/two_water/9540297

posted @ 2017-04-18 08:34  天涯海角路  阅读(97)  评论(0)    收藏  举报