[英]Memory optimization for static images in listview
我有2個僅包含圖像的列表視圖
列表視圖中靜態圖像內存優化的最佳解決方案
每次出現內存不足問題
每個解決方案都涉及動態圖像或從Web服務加載圖像
靜態圖片呢?
我在列表視圖中大約有70-80張圖像(總計)
不需要代碼,因為我只是用圖像填充listview,不使用任何Web服務。
代碼:
private ListView lv;
private ArrayList<Integer> cd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select);
lv = (ListView) findViewById(R.id.lv);
cd = new ArrayList<Integer>();
cd1.add(R.drawable.fuld1);
cd1.add(R.drawable.ful2);
cd1.add(R.drawable.fu4);
lv.setAdapter(new Select(this, cd1));
lv.setOnItemClickListener(this);
}
適配器類別:
公共類SelectAdapter擴展BaseAdapter {
private Activity activity;
private LayoutInflater inflater;
private ViewHolder holder;
private ArrayList<Integer> list;
public SelectAdapter(Activity activity, ArrayList<Integer> list) {
this.activity = activity;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.list = list;
}
@Override
public int getCount() {
return 43;
}
@Override
public Object getItem(int arg0) {
return arg0;
}
@Override
public long getItemId(int arg0) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.select_item, parent,
false);
holder = new ViewHolder();
holder.iv = (ImageView) convertView
.findViewById(R.id.ivSelect;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.iv.setBackgroundResource(list.get(position));
return convertView;
}
private class ViewHolder {
ImageView ivCard;
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
}
日志:
java.lang.OutOfMemoryError: Failed to allocate a 34560012 byte allocation with 4194304 free bytes and 14MB until OOM
您需要使用BitmapFactory.Options。 BitmapFactory.Options可用於處理位圖大小和其他屬性,而無需借助inJustDecodeBounds將它們加載到內存中。 為了消除OutOfMemory錯誤,您需要從資源(可繪制文件夾)中加載按比例縮小的位圖版本。 這可以通過inSampleSize來實現。 如果inSampleSize> 1,則它要求解碼器將按比例縮小的版本加載到內存中,從而避免OutOfMemory錯誤。
瀏覽以下網頁以獲取更多詳細信息:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
演示代碼:
您將需要以下兩種方法來處理每個位圖或可繪制文件:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
validateInSampleSize方法用於計算每個位圖所需的inSampleSize。 最終的inSampleSize值將是最合適的值,或者是將位圖縮放到指定要求的最合適值,就像您將在完全相同的方法中借助參數指定的那樣。
方法encodeSampleBitmapFromResource將從應用程序的資源中解碼位圖文件,並讓您計算inSampleSize而不為位圖分配內存。 只有為特定位圖計算了正確的inSampleSize后,才會分配該位圖的內存。 這是通過BitmapFactory.Options對象的inJustDecodeBounds屬性幫助完成的。
現在,您只需要使用這些方法即可將位圖添加到列表視圖中。 為了舉例說明,假設您在ListView的每個元素或每一行中都有一個ImageView。 現在,我們將像這樣將位圖添加到ImageView中:
imageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),
resID, imageView.getMaxWidth(), imageView.getMaxHeight()));
在這里,resID將是您的位圖的資源ID,以及我目前使用ImageView本身的寬度和高度的寬度和高度的資源ID,因為我個人認為這是最好的解決方案。 但是,您可以使用任何值。 確保您的width和height值不超過將放置位圖的視圖的寬度和高度。
更新的代碼段:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.select_item, parent,
false);
holder = new ViewHolder();
holder.ivCard = (ImageView) convertView
.findViewById(R.id.ivSelect);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.ivCard.setImageBitmap(decodeSampledBitmapFromResource(parent.getResources(),
list.get(position), holder.ivCard.getMaxWidth(), holder.ivCard.getMaxHeight()));
return convertView;
}
查看getView方法的最后一行。 ivCard是ViewHolder中用於適配器的ImageView,它現在將使用setImageBitmap方法將資源設置為ImageView上的位圖。
如果您一次只在屏幕上顯示5-10張圖像,並且每張圖像最多僅幾百kb,那么使用正常的回收列表視圖就足以避免OOM。
首先將所有可繪制資源ID添加到列表視圖
imageResList.add(R.drawable.fulllogocard1)
imageResList.add(R.drawable.fulllogocard2)
imageResList.add(R.drawable.fulllogocard3)
imageResList.add(R.drawable.fulllogocard4)
......
然后,按以下方式實現您的適配器:
public ImageViewAdapter extends BaseAdapter
{
@Override
public int getCount()
{
return imageList.size();
}
@Override
public Object getItem(int i)
{
return null;
}
@Override
public long getItemId(int i)
{
return 0;
}
@Override
public View getView(int i, View existingView, ViewGroup viewGroup)
{
if(existingView == null)
{
ImageView imageView = new ImageView(viewGroup.getContext());
imageView.setImageResource(imageResList.get(i));
return imageView;
}
else
{
ImageView imageView = ((ImageView) existingView);
imageView.setImageResource(imageResList.get(i));
return imageView;
}
}
}
適配器僅回收現有的listView視圖,因此在任何給定的時間點,在給定的時間僅在屏幕上呈現可見的視圖(因此也只有可見的圖像)。
這只是一個解決方法/黑客。 理想情況下,您需要使用為此目的而構建的圖像庫,例如通用圖像加載器,滑行,畢加索或壁畫
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.