2013-04-16 81 views
0

我正在構建一種Pulse的UI。爲此,我在ListView內部使用Gallery。但是,我正面臨着一個奇怪的問題,當我滾動瀏覽listview時,我的應用中的內存分配從9 MB逐漸增加到64 MB,直到它終於崩潰。ListView - outOfMemory異常

什麼不工作:

  • 我懷疑這是否是因爲我使用的位圖。所以,我測試了它沒有圖像內的圖像。我也用Universal Image Loader庫。但是,沒有任何改變。

  • 我讀過類似的問題在SO中,禁用listView的scrollingCache可能會有所幫助。但是,仍然沒有效果。

什麼工作:

  • 設計使用ViewHoldergetTag()setTag()解決內存問題有效的適配器。但是,它帶來了一個奇怪的問題,即listView有時會顯示空行或重複行,從而在UI中顯示錯誤的數據。我該如何解決這個問題?有沒有更好的方法來解決這個問題?

ListViewAdapter.java

public class ListViewAdapter extends BaseAdapter { 
    String user_locale; 
    Context context; 
    LayoutInflater inflater; 
    AssetsAdapter assestsAdapter; 
    List<Category> categoryList; 
    List<BaseAssets> baseAssetList; 
    AssetsTable assetTable; 
    ViewHolder viewHolder; 

public ListViewAdapter(Context context, List<Category> categoryList) { 
    this.context = context; 
    user_locale = Universal.getCurrentLanguage(context); 
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    this.categoryList = categoryList; 
    assetTable = new AssetsTable(context); 
    viewHolder = new ViewHolder(); 
} 

public int getCount() { 
    return categoryList.size(); 
} 

public Object getItem(int position) { 
    return position; 
} 

public long getItemId(int position) { 
    return position; 
} 

public View getView(final int position, View convertView, ViewGroup parent) { 
    String catID = categoryList.get(position).catID; 

    if (convertView == null) 
    { 
     convertView = inflater.inflate(R.layout.category_list_item, parent, false); 
     viewHolder.categoryTitle = (TextView) convertView.findViewById(R.id.category_title); 
     viewHolder.gallery = (Gallery) convertView.findViewById(R.id.gallery); 
     convertView.setTag(viewHolder); 
    } else 
     viewHolder = (ViewHolder) convertView.getTag(); 

    assetTable = new AssetsTable(context); 
    int count = assetTable.getCountOfParticularCategory(catID); 

    initializeGallery(catID); 

    String text = categoryList.get(position).catName + " (" + count + ") "; 
    viewHolder.categoryTitle.setText(text); 
    return convertView; 

} 

public void initializeGallery(String catID) { 
    assetTable = new AssetsTable(context); 
    baseAssetList = assetTable.getAllBaseAssets(catID); 
    assestsAdapter = new AssetsAdapter(context, baseAssetList); 
    adjustGalleryHeight(); 
    viewHolder.gallery.setAdapter(assestsAdapter); 
} 

public void adjustGalleryHeight() { 
    boolean isPortrait = false; 
    final String TAG_PORTRAIT = "portrait"; 

    for (BaseAssets b : baseAssetList) 
    { 
     if (b.thumbOrientation.equals(TAG_PORTRAIT)) 
      isPortrait = true; 
    } 

    final float scale = context.getResources().getDisplayMetrics().density; 
    if (isPortrait) 
    { 
     RelativeLayout.LayoutParams params1 = (RelativeLayout.LayoutParams) viewHolder.gallery.getLayoutParams(); 
     params1.height = (int) (350 * scale); 
     viewHolder.gallery.setLayoutParams(params1); 
    } else 
    { 
     RelativeLayout.LayoutParams params1 = (RelativeLayout.LayoutParams) viewHolder.gallery.getLayoutParams(); 
     params1.height = (int) (280 * scale); 
     viewHolder.gallery.setLayoutParams(params1); 
    } 
} 

class ViewHolder { 
    TextView categoryTitle; 
    Gallery gallery; 

} 

}

GalleryAdapter.java:

public class GalleryAdapter extends BaseAdapter { 

final String TAG_PORTRAIT = "portrait"; 
LayoutInflater inflater; 
ImageLoader imageLoader; 
DisplayImageOptions options; 
Context context; 
List<BaseAssets> baseAssetsList; 

Gallery.LayoutParams params; 

public GalleryAdapter(Context context, List<BaseAssets> baseAssetsList) { 
    imageLoader = ImageLoader.getInstance(); 
    options = new DisplayImageOptions.Builder().cacheOnDisc().imageScaleType(ImageScaleType.EXACTLY).bitmapConfig(Bitmap.Config.RGB_565).cacheInMemory().showStubImage(
      R.drawable.no_preview).build(); 
    this.context = context; 
    this.baseAssetsList = baseAssetsList; 
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

} 

public int getCount() { 
    return baseAssetsList.size(); 
} 

public Object getItem(int position) { 
    return position; 
} 

public long getItemId(int position) { 
    return position; 
} 

public View getView(final int position, View convertView, ViewGroup parent) { 

    ViewHolder viewHolder; 
    if (convertView == null) 
    { 
     viewHolder = new ViewHolder(); 
     convertView = inflater.inflate(R.layout.gallery_list_item, parent, false); 
     viewHolder.galleryWrapper = (RelativeLayout) convertView.findViewById(R.id.gallery_wrapper); 
     viewHolder.downloadThumbnail = (ImageView) convertView.findViewById(R.id.thumbnailDownloadStatus); 
     viewHolder.assetImage = (ImageView) convertView.findViewById(R.id.thumbnail_image); 
     viewHolder.assetName = (TextView) convertView.findViewById(R.id.thumbnail_name); 
     convertView.setTag(viewHolder); 
    } else 
     viewHolder = (ViewHolder) convertView.getTag(); 

    final float scale = context.getResources().getDisplayMetrics().density; 

    if (baseAssetsList.get(position).thumbOrientation.equals(TAG_PORTRAIT)) 
    { 

     params = new Gallery.LayoutParams((int) (166 * scale), (int) (245 * scale)); 
     viewHolder.galleryWrapper.setLayoutParams(params); 

    } else 
    { 
     params = new Gallery.LayoutParams((int) (238 * scale), (int) (191 * scale)); 
     viewHolder.galleryWrapper.setLayoutParams(params); 
    } 

    viewHolder.assetName.setText(baseAssetsList.get(position).contentTitle); 
    String raw_url = baseAssetsList.get(position).thumbnail; 
    String correctUrl = correctUrl(raw_url); 
    imageLoader.displayImage(correctUrl, viewHolder.assetImage, options); 

    convertView.setOnClickListener(new View.OnClickListener() { 

     public void onClick(View v) { 
      Intent intent = new Intent(context, DownloadActivity.class); 
      intent.putExtra(Universal.ASSET_TYPE, baseAssetsList.get(position).contentType); 
      intent.putExtra(Universal.ASSET_TITLE, baseAssetsList.get(position).contentTitle); 
      intent.putExtra(Universal.ASSET_URL, baseAssetsList.get(position).path); 
      intent.putExtra(Universal.ASSET_LARGE_THUMBNAIL, baseAssetsList.get(position).thumbnail); 

      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 

      context.startActivity(intent); 

     } 
    }); 

    return convertView; 
} 

public String correctUrl(String raw_url) { 
    String corrected_url = raw_url; 
    if (!raw_url.contains("http:/")) 
     corrected_url = ("http:/" + raw_url); 
    return corrected_url; 
} 

class ViewHolder { 
    RelativeLayout galleryWrapper; 
    ImageView assetImage; 
    ImageView downloadThumbnail; 
    TextView assetName; 

} 

}

+0

這是因爲'initializeGallery(catID)'調用。在這個方法裏面,你正在創建對象,並且你正在從getView中調用它...這是一個非常糟糕的主意,當你滾動你的列表時(當你滾動多次調用getView時)它會產生很多垃圾。 –

+1

https://github.com/nostra13/Android-Universal-Image-Loader/在有用的信息下檢查第4個點 – Raghunandan

+0

@Raghunandan我試過徹底刪除這個庫和所有的imageViews。我也嘗試了大部分要點。然而沒有幫助! – gauravsapiens

回答

1

嘗試更改「viewHolder = new ViewHolder();」如果convertview爲null,則在Adapter的getview內部;

像:

public View getView(final int position, View convertView, ViewGroup parent) { 
String catID = categoryList.get(position).catID; 

if (convertView == null) 
{ 
    viewHolder = new ViewHolder(); //Add this line. Otherwise u are sharing the same instance for other views. 
    convertView = inflater.inflate(R.layout.category_list_item, parent, false); 
    viewHolder.categoryTitle = (TextView) convertView.findViewById(R.id.category_title); 
    viewHolder.gallery = (Gallery) convertView.findViewById(R.id.gallery); 
    convertView.setTag(viewHolder); 
} else 
    viewHolder = (ViewHolder) convertView.getTag(); 

assetTable = new AssetsTable(context); 
int count = assetTable.getCountOfParticularCategory(catID); 

initializeGallery(catID); 

String text = categoryList.get(position).catName + " (" + count + ") "; 
viewHolder.categoryTitle.setText(text); 
return convertView; 

}

+0

哈哈哈......它的工作原理......沒想到那個問題會那麼簡單..謝謝! 雖然我不明白我是重新初始化viewHolder中的所有組件。但是,他們重複了。你有什麼想法,爲什麼? – gauravsapiens

+0

通過重新初始化,您只是在convertview不爲null的情況下更改與ViewHolder中的控件關聯的值。因此,在更改一個視圖持有者的值時,由於相同的視圖持有者與其他視圖相關聯,數據將會重複。 –

2

在你ListViewAdapter你是不是在getView()調用

viewHolder = new ViewHolder(); 

convertViewnull

檢查它!這可能是問題所在。

+0

嘿,謝謝! 你剛剛錯過了幾分鐘。 :) 雖然感謝一噸! – gauravsapiens

+0

歡迎您!這是Eldhose M Babu的權利,他回答說,他應得的。也感謝你,你也提高了我的答案。 –