Android进阶:ListView性能优化异步加载图片 使滑动效果流畅

    xiaoxiao2021-12-14  17

    ListView 是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的

     

    所以这里就需要把这些信息利用多线程实现异步加载

     

    实现这样功能的类

     

     

    view plain copy to clipboard print ? public class AsyncImageLoader {      private HashMap<String, SoftReference<Drawable>> imageCache;         public AsyncImageLoader() {          imageCache = new HashMap<String, SoftReference<Drawable>>();      }         public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {          if (imageCache.containsKey(imageUrl)) {              SoftReference<Drawable> softReference = imageCache.get(imageUrl);              Drawable drawable = softReference.get();              if (drawable != null) {                  return drawable;              }          }          final Handler handler = new Handler() {              @Override              public void handleMessage(Message message) {                  imageCallback.imageLoaded((Drawable) message.obj, imageUrl);              }          };          new Thread() {              @Override              public void run() {                  Drawable drawable = loadImageFromUrl(imageUrl);                  imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));                  Message message = handler.obtainMessage(0, drawable);                  handler.sendMessage(message);              }          }.start();          return null;      }         public static Drawable loadImageFromUrl(String url) {          // ...       }         public interface ImageCallback {          public void imageLoaded(Drawable imageDrawable, String imageUrl);      }  }  

    [java] view plain copy print ? public class AsyncImageLoader {    private HashMap<String, SoftReference<Drawable>> imageCache;     public AsyncImageLoader() {        imageCache = new HashMap<String, SoftReference<Drawable>>();    }     public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {        if (imageCache.containsKey(imageUrl)) {            SoftReference<Drawable> softReference = imageCache.get(imageUrl);            Drawable drawable = softReference.get();            if (drawable != null) {                return drawable;            }        }        final Handler handler = new Handler() {            @Override            public void handleMessage(Message message) {                imageCallback.imageLoaded((Drawable) message.obj, imageUrl);            }        };        new Thread() {            @Override            public void run() {                Drawable drawable = loadImageFromUrl(imageUrl);                imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));                Message message = handler.obtainMessage(0, drawable);                handler.sendMessage(message);            }        }.start();        return null;    }     public static Drawable loadImageFromUrl(String url) {        // ...    }     public interface ImageCallback {        public void imageLoaded(Drawable imageDrawable, String imageUrl);    }}   public class AsyncImageLoader { private HashMap<String, SoftReference<Drawable>> imageCache; public AsyncImageLoader() { imageCache = new HashMap<String, SoftReference<Drawable>>(); } public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) { if (imageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = imageCache.get(imageUrl); Drawable drawable = softReference.get(); if (drawable != null) { return drawable; } } final Handler handler = new Handler() { @Override public void handleMessage(Message message) { imageCallback.imageLoaded((Drawable) message.obj, imageUrl); } }; new Thread() { @Override public void run() { Drawable drawable = loadImageFromUrl(imageUrl); imageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); Message message = handler.obtainMessage(0, drawable); handler.sendMessage(message); } }.start(); return null; } public static Drawable loadImageFromUrl(String url) { // ... } public interface ImageCallback { public void imageLoaded(Drawable imageDrawable, String imageUrl); }}

     

    注意这里使用了 SoftReference来缓存图片,允许 GC在需要的时候可以对缓存中的图片进行清理。它这样工作:

    ·         调用 loadDrawable(ImageUrl, imageCallback),传入一个匿名实现的 ImageCallback接口

    ·         如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过 ImageCallback回调

    ·         如果图片确实存在于缓存中,就会马上返回,不会回调 ImageCallback

     

            然后我们还可以根据09google I/0开发者大会提到的方式来继续优化Adapter 使用ViewHolder来减少一些比较费时的操作,譬如inflate XML 和 findViewById()等操作

          

    view plain copy to clipboard print ? public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {         private ListView listView;      private AsyncImageLoader asyncImageLoader;         public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {          super(activity, 0, imageAndTexts);          this.listView = listView;          asyncImageLoader = new AsyncImageLoader();      }         @Override      public View getView(int position, View convertView, ViewGroup parent) {          Activity activity = (Activity) getContext();             // Inflate the views from XML           View rowView = convertView;          ViewCache viewCache;          if (rowView == null) {              LayoutInflater inflater = activity.getLayoutInflater();              rowView = inflater.inflate(R.layout.image_and_text_row, null);              viewCache = new ViewCache(rowView);              rowView.setTag(viewCache);          } else {              viewCache = (ViewCache) rowView.getTag();          }          ImageAndText imageAndText = getItem(position);             // Load the image and set it on the ImageView           String imageUrl = imageAndText.getImageUrl();          ImageView imageView = viewCache.getImageView();          imageView.setTag(imageUrl);          Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {              public void imageLoaded(Drawable imageDrawable, String imageUrl) {                  ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);                  if (imageViewByTag != null) {                      imageViewByTag.setImageDrawable(imageDrawable);                  }              }          });          imageView.setImageDrawable(cachedImage);             // Set the text on the TextView           TextView textView = viewCache.getTextView();          textView.setText(imageAndText.getText());             return rowView;      }  }   

    [java] view plain copy print ? public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {     private ListView listView;    private AsyncImageLoader asyncImageLoader;     public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {        super(activity, 0, imageAndTexts);        this.listView = listView;        asyncImageLoader = new AsyncImageLoader();    }     @Override    public View getView(int position, View convertView, ViewGroup parent) {        Activity activity = (Activity) getContext();         // Inflate the views from XML        View rowView = convertView;        ViewCache viewCache;        if (rowView == null) {            LayoutInflater inflater = activity.getLayoutInflater();            rowView = inflater.inflate(R.layout.image_and_text_row, null);            viewCache = new ViewCache(rowView);            rowView.setTag(viewCache);        } else {            viewCache = (ViewCache) rowView.getTag();        }        ImageAndText imageAndText = getItem(position);         // Load the image and set it on the ImageView        String imageUrl = imageAndText.getImageUrl();        ImageView imageView = viewCache.getImageView();        imageView.setTag(imageUrl);        Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {            public void imageLoaded(Drawable imageDrawable, String imageUrl) {                ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);                if (imageViewByTag != null) {                    imageViewByTag.setImageDrawable(imageDrawable);                }            }        });        imageView.setImageDrawable(cachedImage);         // Set the text on the TextView        TextView textView = viewCache.getTextView();        textView.setText(imageAndText.getText());         return rowView;    }}    public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> { private ListView listView; private AsyncImageLoader asyncImageLoader; public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) { super(activity, 0, imageAndTexts); this.listView = listView; asyncImageLoader = new AsyncImageLoader(); } @Override public View getView(int position, View convertView, ViewGroup parent) { Activity activity = (Activity) getContext(); // Inflate the views from XML View rowView = convertView; ViewCache viewCache; if (rowView == null) { LayoutInflater inflater = activity.getLayoutInflater(); rowView = inflater.inflate(R.layout.image_and_text_row, null); viewCache = new ViewCache(rowView); rowView.setTag(viewCache); } else { viewCache = (ViewCache) rowView.getTag(); } ImageAndText imageAndText = getItem(position); // Load the image and set it on the ImageView String imageUrl = imageAndText.getImageUrl(); ImageView imageView = viewCache.getImageView(); imageView.setTag(imageUrl); Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() { public void imageLoaded(Drawable imageDrawable, String imageUrl) { ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl); if (imageViewByTag != null) { imageViewByTag.setImageDrawable(imageDrawable); } } }); imageView.setImageDrawable(cachedImage); // Set the text on the TextView TextView textView = viewCache.getTextView(); textView.setText(imageAndText.getText()); return rowView; }} 

     

     

          这里我们没有加载完iamge之后直接设定到相应的ImageView上 ,而是通过Tag查找,这里我们重用的View 这里有个listView的引用来通过Tag查找 可见 CallBack的实现

     

         

    view plain copy to clipboard print ? ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);                 if (imageViewByTag != null) {                     imageViewByTag.setImageDrawable(imageDrawable);                 }  

    [c-sharp] view plain copy print ? ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);                if (imageViewByTag != null) {                    imageViewByTag.setImageDrawable(imageDrawable);                }   ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl); if (imageViewByTag != null) { imageViewByTag.setImageDrawable(imageDrawable); }

     

          这里通过ViewCatch来减少了 findViewById的使用

     

        

    view plain copy to clipboard print ? public class ViewCache {         private View baseView;      private TextView textView;      private ImageView imageView;         public ViewCache(View baseView) {          this.baseView = baseView;      }         public TextView getTextView() {          if (textView == null) {              textView = (TextView) baseView.findViewById(R.id.text);          }          return titleView;      }         public ImageView getImageView() {          if (imageView == null) {              imageView = (ImageView) baseView.findViewById(R.id.image);          }          return imageView;      }  }   

    [c-sharp] view plain copy print ? public class ViewCache {     private View baseView;    private TextView textView;    private ImageView imageView;     public ViewCache(View baseView) {        this.baseView = baseView;    }     public TextView getTextView() {        if (textView == null) {            textView = (TextView) baseView.findViewById(R.id.text);        }        return titleView;    }     public ImageView getImageView() {        if (imageView == null) {            imageView = (ImageView) baseView.findViewById(R.id.image);        }        return imageView;    }}    public class ViewCache { private View baseView; private TextView textView; private ImageView imageView; public ViewCache(View baseView) { this.baseView = baseView; } public TextView getTextView() { if (textView == null) { textView = (TextView) baseView.findViewById(R.id.text); } return titleView; } public ImageView getImageView() { if (imageView == null) { imageView = (ImageView) baseView.findViewById(R.id.image); } return imageView; }} 

     

         总结 :这里主要做了三点优化

     

     

    在单一线程里加载图片   重用列表中行 缓存行中的 View

     

    转载请注明原文地址: https://ju.6miu.com/read-963691.html

    最新回复(0)