使用自定义适配器使用更多RAM?

时间:2011-07-01 15:31:52

标签: android listview ram

我在第一个午餐的应用程序使用6.5mb,然后当我输入一个包含3个选项卡的活动时,带有显示列表视图的选项卡,它使用14 mb !!

当我从使用SimpleAdapter的“错误代码”转到我的自定义适配器时,就发生了这种情况。

我想要的是列表视图中每侧2个字符串。字符串是一个数组,这是我使用的方式,人们告诉我这是一个不正确的方法:

String[] array= getResources().getStringArray(R.array.Names_List);

int lengthtmp= array.length;
for(int i=0;i<lengthtmp;i++)
{
    counter++;
    AddToList(array[i]);            
}

adapter = new SimpleAdapter(this,list,R.layout.start_row,new String[] {"number","suraname"},new int[] {R.id.Start_Numbering,R.id.Start_Name});


private void AddToList(String name) {
HashMap<String,String> temp = new HashMap<String,String>();


temp.put("number", Integer.toString(SortingPictures[counter-1]));

temp.put("suraname", name);
list.add(temp);

  }

使用此代码,活动需要10mb的内存。更改我的代码以使用自定义适配器后,它使用14 MB:

 public class ListView_Start_Adapter extends BaseAdapter{
private String[] SuraNames;
private int[] PageNumber;
private Context mContext;
RelativeLayout relativeView;
TextView tv_SuraName;
TextView tv_PageNumber;
RelativeLayout.LayoutParams param;

public ListView_Start_Adapter(Context context, String[] SuraNames, int[] PageNumber){
    mContext=context;
    this.SuraNames=SuraNames;
    this.PageNumber=PageNumber;
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return SuraNames.length;
}

@Override
public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return SuraNames[arg0];
}

@Override
public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return PageNumber[arg0];
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    relativeView= new RelativeLayout(mContext);
    tv_SuraName = new TextView(mContext);
    tv_PageNumber = new TextView(mContext);

    tv_SuraName.setText(SuraNames[position]);
    tv_PageNumber.setText(Integer.toString(PageNumber[position]));

    param = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
    param.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);

    relativeView.addView(tv_SuraName, param);
    relativeView.addView(tv_PageNumber);

    return relativeView;

}

  }

任何人都可以告诉我为什么使用自定义适配器时会使用这么多ram?这个自定义适配器有什么问题吗?

EDIT1:这是一个比dziobas建议的更好的代码:

 @Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder     holder;

    if(convertView == null) {
        convertView = mInflater.inflate(R.layout.start_row, parent,false);
        holder=new ViewHolder();

        holder.tv_SuraName   =(TextView)convertView.findViewById(R.id.Start_Name);
        holder.tv_PageNumber = (TextView)convertView.findViewById(R.id.Start_Numbering);
        convertView.setTag(holder);
    } else {
        holder  = (ViewHolder) convertView.getTag();
    }

    holder.tv_SuraName.setText(SuraNames[position]);
    holder.tv_PageNumber.setText(Integer.toString(PageNumber[position]));

    return convertView;
}

我在这一行得到了ExceptionNullPointer:“convertView = mInflater.inflate(R.layout.start_row,parent,false); “为什么?

3 个答案:

答案 0 :(得分:3)

您没有在getView中回收视图。

这样会好得多:

public class ListView_Start_Adapter extends BaseAdapter {
    private String[]            SuraNames;
    private int[]               PageNumber;
    RelativeLayout.LayoutParams param;
    Context                     mContext;

    public ListView_Start_Adapter(Context context, String[] SuraNames, int[] PageNumber) {
        mContext        = context;
        this.SuraNames  = SuraNames;
        this.PageNumber = PageNumber;
        param           = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
        param.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    }

    @Override
    public int getCount() {
        return SuraNames.length;
    }

    @Override
    public Object getItem(int arg0) {
        return SuraNames[arg0];
    }

    @Override
    public long getItemId(int arg0) {
        return PageNumber[arg0];
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder     holder;
        RelativeLayout rowView;

        if(convertView == null) {
            //create view
            rowView              = new RelativeLayout(mContext);
            holder               = new ViewHolder();
            holder.tv_SuraName   = new TextView(mContext);
            holder.tv_PageNumber = new TextView(mContext);
            rowView.addView(holder.tv_SuraName, param);
            rowView.addView(holder.tv_PageNumber);
            rowView.setTag(holder);
        } else {
            //recycle view
            rowView = (RelativeLayout) convertView;
            holder  = (ViewHolder) convertView.getTag();
        }

        //fill views
        holder.tv_SuraName.setText(SuraNames[position]);
        holder.tv_PageNumber.setText(Integer.toString(PageNumber[position]));

        return rowView;
    }

    class ViewHolder {
        RelativeLayout relativeView;
        TextView       tv_SuraName;
        TextView       tv_PageNumber;
    }
}

并更改视图创建。使用LayoutInflater并使用xml进行布局。

有关listview适配器效率的详细信息,请参阅this presentation

答案 1 :(得分:2)

不要为每个条目生成UI元素

您为每个条目返回一个新的relativeView。这将

  1. 使用更多内存
  2. 对垃圾收集器施加更大压力
  3. 使用常规方式实现getView

    // In the class
    private LayoutInflater inflater;
    
    // in the constructor
        inflater = (LayoutInflater)
            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
    // getView()
        if (view == null) {
            view = inflater.inflate(R.layout.element_layout, parent, false);
        }
    

    SimpleAdapter源代码可用

    看看SimpleAdapter.java。源代码是免费提供的。几乎每个Adapter都有这些代码块。

    快乐的黑客攻击!

答案 2 :(得分:0)

您可能想要做的第一件事是开始使用传递给getView的convertView而不是创建新视图。您将获得更高的性能(从更少的垃圾收集和更少的视图构造),并可能降低内存使用率。