2014-01-14 97 views
0

我的應用程序中有一個自定義的列表視圖,它顯示圖像和文本(Json)。我從URL獲得的圖像正在工作,但listview是laggy(滾動滯後)。 也許我的問題是ImageLoader.java類 這是我的代碼:ListView在android中的滾動滯後

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.aaaaaaaaaaaaaaa; 

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 (Throwable ex) { 
     ex.printStackTrace(); 
     if (ex instanceof OutOfMemoryError) 
      memoryCache.clear(); 
     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; 
     FileInputStream stream1 = new FileInputStream(f); 
     BitmapFactory.decodeStream(stream1, null, o); 
     stream1.close(); 

     // 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; 
     FileInputStream stream2 = new FileInputStream(f); 
     Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2); 
     stream2.close(); 
     return bitmap; 
    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    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() { 
     try { 
      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); 
     } catch (Throwable th) { 
      th.printStackTrace(); 
     } 
    } 
} 

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(); 
} 

} 

這是也是我BaseAdapter.java類

public class BRIgeAdapter extends BaseAdapter { 
private LayoutInflater inflater; 
private Activity activity; 
public ArrayList<HashMap<String, String>> data; 
public ViewHolder holder; 
public ImageLoader imageLoader; 
HashMap<String, String> itemList; 
private int screenSize; 
MainActivity main; 
public BRIgeAdapter(Activity a, ArrayList<HashMap<String, String>> d,int screenSize) { 
    this.activity = a; 
    this.data = d; 
    this.screenSize = screenSize; 
    inflater = (LayoutInflater) activity 
      .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    imageLoader = new ImageLoader(activity.getApplicationContext()); 
} 
public int getCount() { 
    return data.size(); 
} 
public Object getItem(int position) { 
    return data.get(position); 
} 
public long getItemId(int position) { 
    return (long) position; 
} 
@Override 
public int getViewTypeCount() { 
    return data.size(); 
} 
@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    if (convertView == null) { 
     holder = new ViewHolder(); 
     main = new MainActivity(); 
     convertView = inflater.inflate(R.layout.list_row, parent, false); 

     holder.journal = (TextView) convertView 
       .findViewById(R.id.smalljournal); 
     holder.statId = (TextView) convertView 
       .findViewById(R.id.smallstatID); 

     holder.smallDescription1 = (TextView) convertView 
     .findViewById(R.id.smallDescription1); 
     holder.DateTime = (TextView) convertView 
       .findViewById(R.id.smallDateTime); 
     holder.thumb_image = (ImageView) convertView 
       .findViewById(R.id.smallthumb); 
     holder.title = (TextView) convertView.findViewById(R.id.smalltitle); 
     holder.description = (TextView) convertView 
       .findViewById(R.id.smallDescription); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 
    itemList = data.get(position); 
    if (itemList != null) { 
     holder.journal.setText(itemList.get(MainActivity.KEY_journal)); 
     // holder.DateTime.setText(itemList.get(MainActivity.KEY_pubDate)); 
     holder.statId.setText(itemList.get(MainActivity.KEY_statID)); 
     holder.smallDescription1.setText(itemList.get(MainActivity.KEY_description)); 
     holder.journal.setTypeface(MainActivity.tf2); 
     String titleString = itemList.get(MainActivity.KEY_title); 
     Calendar cal = new GregorianCalendar(2013, 11, 20); 
     DateFormat df = new SimpleDateFormat("dd.MM.yyyy"); 
     // DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); 
     String date = df.format(cal.getTime()); 
     String DateTime = itemList.get(MainActivity.KEY_pubDate); 
     DateTime = date; 
     holder.DateTime.setText(DateTime); 
     holder.title.setText(titleString); 
     holder.title.setTypeface(MainActivity.tf2); 

     holder.title.setLineSpacing(2, 1.2f); 
     holder.description.setLineSpacing(2, 1.2f); 

     if(screenSize == Configuration.SCREENLAYOUT_SIZE_NORMAL) 
      holder.description.setVisibility(View.INVISIBLE); 
     else 
      holder.description.setText(itemList.get(MainActivity.KEY_description)); 

     holder.description.setTypeface(MainActivity.tf2); 
     imageLoader.DisplayImage(itemList.get(MainActivity.KEY_image), 
       holder.thumb_image); 
    } 
    return convertView; 
} 
static class ViewHolder { 
    public TextView journal, title, description,smallDescription1, DateTime, statId; 
    ImageView thumb_image; 
} 
} 

是否有任何可能的方式,我可以減少或消除這種滯後?

+1

你試過AsyncTask嗎? –

+0

是的當然。我在我的MainActivity.java類上使用AsyncTask我的問題是小尺寸屏幕分辨率滾動是完美的,但大尺寸屏幕結果(例如Nexus 7)listview是lagy –

+0

不知道如果這就是你想要的,但你可以嘗試'持有人.thumb_image.setScaleType(ScaleType.FIT_XY)',這將使圖像適合ImageView –

回答

0

我看到您使用線程從url加載圖像。我推薦你使用Android Universal Image Loader Library。它非常靈活,而且不太明顯。你可以找到整個信息Here

+0

我不知道如何使用這個庫。不幸的是,我沒有時間去學習這個庫(我幾乎沒有時間) –

+0

@JambulKukhalashvili我想你會花更多的時間來使用刪除你自己版本的listview中的滯後,而不是學習使用這個庫。這只是我的看法,但是這個庫爲我節省了很多時間,只需從我發佈的鏈接下載源代碼並查看示例應用程序即可。我認爲這會幫助你理解很多 – Arshak92

+0

,但是我想改變我的代碼來完美(沒有listview滯後),這是不可能的? –

1

如果你使用的是xml,那麼將ListView的寬度和高度設置爲match_parent。

+0

我改變了它。不幸的是,我沒有設備tu測試它在模擬器項目工作完美,在你的選擇你的解決方案是正確的? –

+0

是的,如果您將其設置爲包裝內容,則必須始終計算寬度並減慢寬度。 – Nfear

0

此外,它看起來像你在getView方法中創建對象。這意味着當繪製每個視圖時,操作系統必須完成爲您創建這些對象的所有工作。如果正在使用大型列表(或小型內存),則會強制垃圾收集器運行,從而導致您的應用程序出現口吃。嘗試將所有對象創建移動到構造函數方法,以便它只運行一次。然後根據需要在get view方法中重新分配它們。 這應該提供一個明顯的速度改進。

祝你好運;)

+0

呵呵?我指的是你的'BRIgeAdapter'類。所有這些 - String titleString = itemList.get(MainActivity.KEY_title); Calendar cal = new GregorianCalendar(2013,11,20); DateFormat df = new SimpleDateFormat(「dd.MM.yyyy」); String date = df.format(cal.getTime()); String DateTime = itemList.get(MainActivity.KEY_pubDate); DateTime = date;應該重新考慮。 – Shmuel

+0

創建Calendar對象的操作很慢,我不建議在getView方法中,減少對象分配肯定會有助於ListView的性能 – Niko