2013-04-16 58 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的权利,他回答说,他应得的。也感谢你,你也提高了我的答案。 –