my application on the first lunch uses 6.5mb, and then when I enter an activity with 3 tabs, with a tab that displays a listview, it uses 14 mb!!
This happened when I went from a "bad code" with SimpleAdapter to my Custom Adapter.
What I want is 2 strings on each side in a listview. the strings are in an array, here is the way I was using that people told me is an incorrect way to do:
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);
}
With this code, the activity takes 10mb of ram. After changing my code to use a Custom adapter, it uses 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;
}
}
Can anyone tell me why so much ram used when using a Custom adapter? Is there something wrong with this Custom adapter?
EDIT1: Is this a better code that the one suggested by 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;
}
I get ExceptionNullPointer in this line: " convertView = mInflater.inflate(R.layout.start_row, parent,false); " Why?
You're not recycling view in getView.
It'll much better like this:
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;
}
}
And change view creation. Use LayoutInflater and use xml for layout.
See this presentation for more info about listview adapter efficiency.
Don't generate a UI element for every entry
You return a fresh relativeView for every single entry. This will
- Use more memory
- Put more pressure on the garbage collector
Use the normal way to implement 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);
}
The SimpleAdapter source code is available
Just look at the SimpleAdapter.java. The sourcecode is freely available. Just about every Adapter has these code block.
Happy hacking!
The first thing that you might want to do is start using the convertView passed into getView instead of creating new views. You'll end up with higher performance (from fewer garbage collections and fewer view constructions) and probably lower memory usage.
精彩评论