Android编程学习之异步加载图片的方法

Android编程学习之异步加载图片的方法,第1张

概述本文实例讲述了Android编程学习异步加载图片的方法。分享给大家供大家参考,具体如下:

本文实例讲述了AndroID编程学习之异步加载图片的方法。分享给大家供大家参考,具体如下:

最近在androID开发中碰到比较棘手的问题,就是加载图片内存溢出。我开发的是一个新闻应用,应用中用到大量的图片,一个界面中可能会有上百张图片。开发androID应用的朋友可能或多或少碰到加载图片内存溢出问题,一般情况下,加载一张大图就会导致内存溢出,同样,加载多张图片内存溢出的概率也很高。

列一下网络上查到的一般做法:

1.使用BitmapFactory.Options对图片进行压缩
2.优化加载图片的adapter中的getVIEw方法,使之尽可能少占用内存
3.使用异步加载图片的方式,使图片在页面加载后慢慢载入进来。

1、2步骤是必须做足的工作,但是对于大量图片的列表仍然无法解决内存溢出的问题,采用异步加载图片的方式才能有效解决图片加载内存溢出问题。

测试的效果图如下:

在这里我把主要的代码贴出来,给大家分享一下。

1、首先是MainActivity和activity_main.xml布局文件的代码。

(1)、MainActivity的代码如下:

package net.loonggg.test; import java.util.List; import net.loonggg.adapter.MyAdapter; import net.loonggg.bean.Menu; import net.loonggg.util.httpUtil; import net.loonggg.util.Utils; import androID.app.Activity; import androID.app.ProgressDialog; import androID.os.AsyncTask; import androID.os.Bundle; import androID.vIEw.Window; import androID.Widget.ListVIEw; public class MainActivity extends Activity {  private ListVIEw lv;  private MyAdapter adapter;  private ProgressDialog pd;  @OverrIDe  protected voID onCreate(Bundle savedInstanceState) {   requestwindowFeature(Window.FEATURE_NO_Title);   super.onCreate(savedInstanceState);   setContentVIEw(R.layout.activity_main);   lv = (ListVIEw) findVIEwByID(R.ID.lv);   pd = new ProgressDialog(this);   pd.setTitle("加载菜单");   pd.setMessage("正在加载");   adapter = new MyAdapter(this);   new MyTask().execute("1");  }  public class MyTask extends AsyncTask<String,VoID,List<Menu>> {   @OverrIDe   protected voID onPreExecute() {    super.onPreExecute();    pd.show();   }   @OverrIDe   protected voID onPostExecute(List<Menu> result) {    super.onPostExecute(result);    adapter.setData(result);    lv.setAdapter(adapter);    pd.dismiss();   }   @OverrIDe   protected List<Menu> doInBackground(String... params) {    String menuListStr = getListdishesInfo(params[0]);    return Utils.getInstance().parseMenusJsON(menuListStr);   }  }  private String getListdishesInfo(String sortID) {   // url   String url = httpUtil.BASE_URL + "servlet/MenuInfoServlet?sortID="     + sortID + "&flag=1";   // 查询返回结果   return httpUtil.queryStringForPost(url);  } } 

(2)、activity_main.xml的布局文件如下:

<linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"  xmlns:tools="http://schemas.androID.com/tools"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent"  androID:background="#ffffff"  androID:orIEntation="vertical" >  <ListVIEw   androID:ID="@+ID/lv"   androID:layout_wIDth="fill_parent"   androID:layout_height="wrap_content" >  </ListVIEw> </linearLayout> 

2、这是自定义的ListVIEw的adapter的代码:

package net.loonggg.adapter; import java.util.List; import net.loonggg.bean.Menu; import net.loonggg.test.R; import net.loonggg.util.ImageLoader; import androID.app.Activity; import androID.content.Context; import androID.vIEw.LayoutInflater; import androID.vIEw.VIEw; import androID.vIEw.VIEwGroup; import androID.Widget.BaseAdapter; import androID.Widget.ImageVIEw; import androID.Widget.TextVIEw; public class MyAdapter extends BaseAdapter {  private List<Menu> List;  private Context context;  private Activity activity;  private ImageLoader imageLoader;  private VIEwHolder vIEwHolder;  public MyAdapter(Context context) {   this.context = context;   this.activity = (Activity) context;   imageLoader = new ImageLoader(context);  }  public voID setData(List<Menu> List) {   this.List = List;  }  @OverrIDe  public int getCount() {   return List.size();  }  @OverrIDe  public Object getItem(int position) {   return List.get(position);  }  @OverrIDe  public long getItemID(int position) {   return position;  }  @OverrIDe  public VIEw getVIEw(int position,VIEw convertVIEw,VIEwGroup parent) {   if (convertVIEw == null) {    convertVIEw = LayoutInflater.from(context).inflate(      R.layout.ListvIEw_item,null);    vIEwHolder = new VIEwHolder();    vIEwHolder.tv = (TextVIEw) convertVIEw.findVIEwByID(R.ID.item_tv);    vIEwHolder.iv = (ImageVIEw) convertVIEw.findVIEwByID(R.ID.item_iv);    convertVIEw.setTag(vIEwHolder);   } else {    vIEwHolder = (VIEwHolder) convertVIEw.getTag();   }   vIEwHolder.tv.setText(List.get(position).getdishes());   imageLoader.displayImage(List.get(position).getPicPath(),activity,vIEwHolder.iv);   return convertVIEw;  }  private class VIEwHolder {   private ImageVIEw iv;   private TextVIEw tv;  } } 

3、这是最重要的一部分代码,这就是异步加载图片的一个类,这里我就不解释了,代码中附有注释。代码如下:

package net.loonggg.util; import java.io.file; import java.io.fileinputStream; import java.io.fileNotFoundException; import java.io.fileOutputStream; import java.io.inputStream; import java.io.OutputStream; import java.net.httpURLConnection; import java.net.URL; import java.util.Collections; import java.util.Map; import java.util.Stack; import java.util.WeakHashMap; import net.loonggg.test.R; import androID.app.Activity; import androID.content.Context; import androID.graphics.Bitmap; import androID.graphics.BitmapFactory; import androID.Widget.ImageVIEw; /**  * 异步加载图片类  *  * @author loonggg  *  */ public class ImageLoader {  // 手机中的缓存  private MemoryCache memoryCache = new MemoryCache();  // sd卡缓存  private fileCache fileCache;  private PicturesLoader pictureLoaderThread = new PicturesLoader();  private PicturesQueue picturesQueue = new PicturesQueue();  private Map<ImageVIEw,String> imageVIEws = Collections    .synchronizedMap(new WeakHashMap<ImageVIEw,String>());  public ImageLoader(Context context) {   // 设置线程的优先级   pictureLoaderThread.setPriority(Thread.norM_PRIORITY - 1);   fileCache = new fileCache(context);  }  // 在找不到图片时,默认的图片  final int stub_ID = R.drawable.stub;  public voID displayImage(String url,Activity activity,ImageVIEw imageVIEw) {   imageVIEws.put(imageVIEw,url);   Bitmap bitmap = memoryCache.get(url);   if (bitmap != null)    imageVIEw.setimageBitmap(bitmap);   else {// 如果手机内存缓存中没有图片,则调用任务队列,并先设置默认图片    queuePhoto(url,imageVIEw);    imageVIEw.setimageResource(stub_ID);   }  }  private voID queuePhoto(String url,ImageVIEw imageVIEw) {   // 这ImageVIEw可能之前被用于其它图像。所以可能会有一些旧的任务队列。我们需要清理掉它们。   picturesQueue.Clean(imageVIEw);   PicturetoLoad p = new PicturetoLoad(url,imageVIEw);   synchronized (picturesQueue.picturesToload) {    picturesQueue.picturesToload.push(p);    picturesQueue.picturesToload.notifyAll();   }   // 如果这个线程还没有启动,则启动线程   if (pictureLoaderThread.getState() == Thread.State.NEW)    pictureLoaderThread.start();  }  /**   * 根据url获取相应的图片的Bitmap   *   * @param url   * @return   */  private Bitmap getBitmap(String url) {   file f = fileCache.getfile(url);   // 从SD卡缓存中获取   Bitmap b = decodefile(f);   if (b != null)    return b;   // 否则从网络中获取   try {    Bitmap bitmap = null;    URL imageUrl = new URL(url);    httpURLConnection conn = (httpURLConnection) imageUrl      .openConnection();    conn.setConnectTimeout(30000);    conn.setReadTimeout(30000);    inputStream is = conn.getinputStream();    OutputStream os = new fileOutputStream(f);    // 将图片写到sd卡目录中去    ImageUtil.copyStream(is,os);    os.close();    bitmap = decodefile(f);    return bitmap;   } catch (Exception ex) {    ex.printstacktrace();    return null;   }  }  // 解码图像和缩放以减少内存的消耗  private Bitmap decodefile(file f) {   try {    // 解码图像尺寸    BitmapFactory.Options o = new BitmapFactory.Options();    o.inJustDecodeBounds = true;    BitmapFactory.decodeStream(new fileinputStream(f),null,o);    // 找到正确的缩放值。这应该是2的幂。    final int required_SIZE = 70;    int wIDth_tmp = o.outWIDth,height_tmp = o.outHeight;    int scale = 1;    while (true) {     if (wIDth_tmp / 2 < required_SIZE       || height_tmp / 2 < required_SIZE)      break;     wIDth_tmp /= 2;     height_tmp /= 2;     scale *= 2;    }    // 设置恰当的inSampleSize可以使BitmapFactory分配更少的空间    // 用正确恰当的inSampleSize进行decode    BitmapFactory.Options o2 = new BitmapFactory.Options();    o2.inSampleSize = scale;    return BitmapFactory.decodeStream(new fileinputStream(f),o2);   } catch (fileNotFoundException e) {   }   return null;  }  /**   * PicturetoLoad类(包括图片的地址和ImageVIEw对象)   *   * @author loonggg   *   */  private class PicturetoLoad {   public String url;   public ImageVIEw imageVIEw;   public PicturetoLoad(String u,ImageVIEw i) {    url = u;    imageVIEw = i;   }  }  public voID stopThread() {   pictureLoaderThread.interrupt();  }  // 存储下载的照片列表  class PicturesQueue {   private Stack<PicturetoLoad> picturesToload = new Stack<PicturetoLoad>();   // 删除这个ImageVIEw的所有实例   public voID Clean(ImageVIEw image) {    for (int j = 0; j < picturesToload.size();) {     if (picturesToload.get(j).imageVIEw == image)      picturesToload.remove(j);     else      ++j;    }   }  }  // 图片加载线程  class PicturesLoader extends Thread {   public voID run() {    try {     while (true) {      // 线程等待直到有图片加载在队列中      if (picturesQueue.picturesToload.size() == 0)       synchronized (picturesQueue.picturesToload) {        picturesQueue.picturesToload.wait();       }      if (picturesQueue.picturesToload.size() != 0) {       PicturetoLoad photoToload;       synchronized (picturesQueue.picturesToload) {        photoToload = picturesQueue.picturesToload.pop();       }       Bitmap bmp = getBitmap(photoToload.url);       // 写到手机内存中       memoryCache.put(photoToload.url,bmp);       String tag = imageVIEws.get(photoToload.imageVIEw);       if (tag != null && tag.equals(photoToload.url)) {        Bitmapdisplayer bd = new Bitmapdisplayer(bmp,photoToload.imageVIEw);        Activity activity = (Activity) photoToload.imageVIEw          .getContext();        activity.runOnUiThread(bd);       }      }      if (Thread.interrupted())       break;     }    } catch (InterruptedException e) {     // 在这里允许线程退出    }   }  }  // 在UI线程中显示Bitmap图像  class Bitmapdisplayer implements Runnable {   Bitmap bitmap;   ImageVIEw imageVIEw;   public Bitmapdisplayer(Bitmap bitmap,ImageVIEw imageVIEw) {    this.bitmap = bitmap;    this.imageVIEw = imageVIEw;   }   public voID run() {    if (bitmap != null)     imageVIEw.setimageBitmap(bitmap);    else     imageVIEw.setimageResource(stub_ID);   }  }  public voID clearCache() {   memoryCache.clear();   fileCache.clear();  } } 

4、紧接着是几个实体类,一个是缓存到SD卡中的实体类,还有一个是缓存到手机内存中的实体类。代码如下:

(1)、缓存到sd卡的实体类:

package net.loonggg.util; import java.io.file; import androID.content.Context; public class fileCache {  private file cacheDir;  public fileCache(Context context) {   // 找到保存缓存的图片目录   if (androID.os.Environment.getExternalStorageState().equals(     androID.os.Environment.MEDIA_MOUNTED))    cacheDir = new file(      androID.os.Environment.getExternalStorageDirectory(),"newnews");   else    cacheDir = context.getCacheDir();   if (!cacheDir.exists())    cacheDir.mkdirs();  }  public file getfile(String url) {   String filename = String.valueOf(url.hashCode());   file f = new file(cacheDir,filename);   return f;  }  public voID clear() {   file[] files = cacheDir.Listfiles();   for (file f : files)    f.delete();  } } 

(2)、缓存到手机内存的实体类:

package net.loonggg.util; import java.lang.ref.softReference; import java.util.HashMap; import androID.graphics.Bitmap; public class MemoryCache {  private HashMap<String,SoftReference<Bitmap>> cache=new HashMap<String,SoftReference<Bitmap>>();  public Bitmap get(String ID){   if(!cache.containsKey(ID))    return null;   SoftReference<Bitmap> ref=cache.get(ID);   return ref.get();  }  public voID put(String ID,Bitmap bitmap){   cache.put(ID,new SoftReference<Bitmap>(bitmap));  }  public voID clear() {   cache.clear();  } } 

5、这个是输入输出流转换的类,及方法:

package net.loonggg.util; import java.io.inputStream; import java.io.OutputStream; public class ImageUtil {  public static voID copyStream(inputStream is,OutputStream os) {   final int buffer_size = 1024;   try {    byte[] bytes = new byte[buffer_size];    for (;;) {     int count = is.read(bytes,buffer_size);     if (count == -1)      break;     os.write(bytes,count);    }   } catch (Exception ex) {   }  } } 

到这里基本就完成了。

希望本文所述对大家AndroID程序设计有所帮助。

总结

以上是内存溢出为你收集整理的Android编程学习之异步加载图片的方法全部内容,希望文章能够帮你解决Android编程学习之异步加载图片的方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1142240.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存