2013-05-16 42 views
2

我正在使用XMLParser获取带有日期的XML列表视图。解析器将日期发送给LazyAdapter,并将LazyAdapter发送到List。滚动时出现Android ListView生涩

当我在我的应用程序中滚动时,ListView ist生涩和缓慢。 我认为问题将是ImageLoader。当我使用ImageLoader禁用该行时,它的工作更好,而且不生涩。

的LazyAdapter:

public View getView(int position, View convertView, ViewGroup parent) { 
     View vi=convertView; 
     if(convertView==null) 


     vi = inflater.inflate(R.layout.list_row, null); 

     TextView id = (TextView)vi.findViewById(R.id.id); 
     TextView title = (TextView)vi.findViewById(R.id.title); 
     TextView artist = (TextView)vi.findViewById(R.id.artist); 
     ImageView thumb_image=(ImageView)vi.findViewById(R.id.list_image); 

     HashMap<String, String> coupon = new HashMap<String, String>(); 
     coupon = data.get(position); 

     id.setText(coupon.get(NewCoupons.id)); 
     title.setText(title); 
     artist.setText(coupon.get(NewCoupons.artist)); 
     imageLoader.DisplayImage(KEY_THUMN, thumb_image); 
     return vi; 
    } 

的ImageLoader的:

public class ImageLoader { 

    MemoryCache memoryCache=new MemoryCache(); 
    FileCache fileCache; 
    private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); 
    ExecutorService executorService; 

    public ImageLoader(Context context){ 
     fileCache=new FileCache(context); 
     executorService=Executors.newFixedThreadPool(5); 
    } 

    final int stub_id = R.drawable.no_image; 
    public void DisplayImage(String url, 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) 
    { 
     PhotoToLoad p=new PhotoToLoad(url, imageView); 
     executorService.submit(new PhotosLoader(p)); 
    } 

    private Bitmap getBitmap(String url) 
    { 
     File f=fileCache.getFile(url); 

     //from SD cache 
     Bitmap b = decodeFile(f); 
     if(b!=null) 
      return b; 

     //from web 
     try { 
      Bitmap bitmap=null; 
      URL imageUrl = new URL(url); 
      HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); 
      conn.setConnectTimeout(30000); 
      conn.setReadTimeout(30000); 
      conn.setInstanceFollowRedirects(true); 
      InputStream is=conn.getInputStream(); 
      OutputStream os = new FileOutputStream(f); 
      Utils.CopyStream(is, os); 
      os.close(); 
      bitmap = decodeFile(f); 
      return bitmap; 
     } catch (Exception ex){ 
      ex.printStackTrace(); 
      return null; 
     } 
    } 

    //decodes image and scales it to reduce memory consumption 
    private Bitmap decodeFile(File f){ 
     try { 
      //decode image size 
      BitmapFactory.Options o = new BitmapFactory.Options(); 
      o.inJustDecodeBounds = true; 
      BitmapFactory.decodeStream(new FileInputStream(f),null,o); 

      //Find the correct scale value. It should be the power of 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; 
      } 

      //decode with inSampleSize 
      BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o2.inSampleSize=scale; 
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 
     } catch (FileNotFoundException e) {} 
     return null; 
    } 

    //Task for the queue 
    private class PhotoToLoad 
    { 
     public String url; 
     public ImageView imageView; 
     public PhotoToLoad(String u, ImageView i){ 
      url=u; 
      imageView=i; 
     } 
    } 

    class PhotosLoader implements Runnable { 
     PhotoToLoad photoToLoad; 
     PhotosLoader(PhotoToLoad photoToLoad){ 
      this.photoToLoad=photoToLoad; 
     } 

     @Override 
     public void run() { 
      if(imageViewReused(photoToLoad)) 
       return; 
      Bitmap bmp=getBitmap(photoToLoad.url); 
      memoryCache.put(photoToLoad.url, bmp); 
      if(imageViewReused(photoToLoad)) 
       return; 
      BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad); 
      Activity a=(Activity)photoToLoad.imageView.getContext(); 
      a.runOnUiThread(bd); 
     } 
    } 

    boolean imageViewReused(PhotoToLoad photoToLoad){ 
     String tag=imageViews.get(photoToLoad.imageView); 
     if(tag==null || !tag.equals(photoToLoad.url)) 
      return true; 
     return false; 
    } 

    //Used to display bitmap in the UI thread 
    class BitmapDisplayer implements Runnable 
    { 
     Bitmap bitmap; 
     PhotoToLoad photoToLoad; 
     public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;} 
     public void run() 
     { 
      if(imageViewReused(photoToLoad)) 
       return; 
      if(bitmap!=null) 
       photoToLoad.imageView.setImageBitmap(bitmap); 
      else 
       photoToLoad.imageView.setImageResource(stub_id); 
     } 
    } 

    public void clearCache() { 
     memoryCache.clear(); 
     fileCache.clear(); 
    } 

} 
+0

http://developer.android.com/training/improving-layouts/平滑scrolling.html。使用视图持有者 – Raghunandan

回答

7

你应该在滚动期间暂停图像加载器。这是保持滚动非常流畅的最佳方式。

为此,您需要在图像加载器中添加setPaused(boolean pause)方法。暂停时,图像加载器应停止处理队列并等待暂停被取消。 通过检查scrollState参数,将在onScrollStateChanged()内执行OnScrollListener来触发此方法。

imageLoader.setPaused(scrollState == OnScrollListener.SCROLL_STATE_FLING); 

欲了解更多信息,我的消息来源是西里尔Mottier所给的介绍:

https://speakerdeck.com/cyrilmottier/optimizing-android-ui-pro-tips-for-creating-smooth-and-responsive-apps

从幻灯片中所看到98


还有一个更简单的方法,但少高效:只需将图像加载器线程优先级设置为较低的值即可。在run()方法begginning添加以下行的Runnable里面执行:

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 
+0

为什么要设置优先级?在他显示图像后不能停止ImageLoader.class? – user1878413

+1

通过降低图像线程的优先级,可以增加分配给主线程(负责列表视图滚动)的CPU时间。 – tbruyelle

+0

当我在ImageLoader的Runable里面设置你的Process.set .....时,他很伤心:THREAD_PRIORITY_BACKGROUND无法解析或者不是字段 – user1878413

0
  1. 首先,你应该使用convertview和ViewHolder

    static class ViewHolder { 
        TextView idTestView; 
        TextView titleTestView; 
        TextView artistTestView; 
    } 
    public View getView(int position, View convertView, ViewGroup parent) { 
        ViewHolder holder; 
    
        if(convertView == null) { 
         convertView = inflater.inflate(R.layout.list_row, null); 
         holder = new ViewHolder(); 
         holder.idTestView = (TextView)convertView.findViewById(R.id.id); 
         holder.titleTestView = (TextView)convertView.findViewById(R.id.title); 
         holder.artistTestView = (TextView)convertView.findViewById(R.id.artist); 
         holder.image = (ImageView)convertView.findViewById(R.id.list_image); 
         convertView.setTag(holder); 
        } else { 
         holder = convertView.getTag(); 
        } 
    
        // initial viewholder attributes 
    

    }

  2. 你应该使用ImageLoader的显示画面,并在内存中缓存也缓存在蒸馏水。你可以从那里得到它:https://github.com/nostra13/Android-Universal-Image-Loader

  3. 您的ListView应该添加setOnScrollListener,滚动飞行时,你不应该加载图片