I want to konw why the following code not work well.
#Override
public void onUpdateView(View view, int position, NewsItemNormal data) {
ImageView image = ViewUtils.findView(view, R.id.newslist_normal_image);
TextView titleText = ViewUtils.findView(view, R.id.newslist_normal_title_text);
TextView timeText = ViewUtils.findView(view, R.id.newslist_normal_time_text);
}
onUpdateView() is a method from getview(), called after the getView() get the convertView.My listview has two headerviews and listview items, one of the headerview is viewpager.When i update the data source, this onUpdateView's image & titleText & timeText return null. Debuged and found the onUpdateView reveived 'view' post from getView() is the headerviews not the item's view.I don't know why, and i worked for android 2 years, i known how to use a adapter with listview.Any help would be great.Thanks.
Follows codes work well.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (null == convertView || !(convertView.getTag(R.id.tag_holder_default) instanceof ViewHolder)) {
holder = new ViewHolder();
convertView.setTag(R.id.tag_holder_default, holder);
} else {
holder = (ViewHolder) convertView.getTag(R.id.tag_holder_default);
}
return convertView;
}
Pay attention to (convertView.getTag(R.id.tag_holder_default) instanceof ViewHolder.
When you add a header view to a ListView, it actually wraps your adapter with a new adapter which contains the header view as the first item. You need to take this into accouut when you deal with the position passed in the getView method.
For more detail, this post might be helpful.
ListView addHeaderView causes position to increase by one?
Related
I'm working with a custom ListView with custom Adapter which only has EditText and TextView in each row, the problem is in scroll, when there is something in the first row, for example, it doesn't matter how long is the text in the field, if it goes out of the screen while scrolling, then if I get back to it, it looses the text it had
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.campos, viewGroup, false);
TextView tv= itemView.findViewById(R.id.lblNumeroCampo);
EditText txtCampo = itemView.findViewById(R.id.txtCampo);
txtCampo.setText(elementos.get(i));
tvNumero.setText("" + (i +1));
return itemView;
}
I just want not to lose text that is in any field of the list, thanks to those who want to help me.
I think you don't need to call the findViewById every time the getview action fired.
You can also use a holder class.
Your UI classes should be called once when the view class is null.
The view class can save the holder class with setTag method then reuse them by getTag.
Here is my suggestion.
class ViewHolder
{
TextView tvNumero;
EditText txtCampo;
}
public View getView(int position, View view, ViewGroup viewGroup) {
ViewHolder holder;
if(view == null)
{
view = inflater.inflate(resource, viewGroup, false);
holder = new ViewHolder();
holder.tvNumero= view.findViewById(R.id.lblNumeroCampo);
holder.txtCampo = view.findViewById(R.id.txtCampo);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.txtCampo.setText(elementos.get(i));
holder.tvNumero.setText("" + (i +1));
return view;
}
Have a good coding.
This happens because android calls getView() everytime the view goes out of visible space and appears again. Since you are creating a new view in your getView() method, there is no recycling happening. Everytime the getView() method is called, a new view is returned with no text in it.
As mentioned by #tommybee, you can use a view holder class that checks to see if the view has already been initialized and return the initialized view if called.
Alternatively, I would suggest you to use RecyclerView instead of ListView, which makes using ViewHolder pattern mandatory. Reason is explained clearly here
I have an Adapter with ViewHolder. Let's say I want to set data only once to the ViewHoler inside the getView() method, what's actually happened is, its set the data every time I'm scrolling the view.
How can I check if the ViewHolder was already init or not?
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Deal deal = dealsArr.get(position);
holder.textView.setText(deal.getPrice);
// Here is my issue. how can I do it only once?
changePrice(deal, true);
}
I asssume you already have the basic understanding of Android Adapters & working of getCount() & getView() if not see this
Either adapter returns a null View or an Inflated View; findViewbyId(R.id.xmlID) is always executed;
ViewHolder is used to avoid frequent call and ensure the smooth scrolling of your listview.
Excellent Explanation here
First spend sometime of understand Listview's recycling mechanism!
The link I had shared also has a link to that.!
public View getView(final int position, View convertView, ViewGroup parent) {
//rest of the code goes here
}
focus on the parameters of this method,
the convertViewwhich is for recycling will be null initially because there is no recycling done yet
so this part of the code will be executed;
if (convertView == null) { //convertView is null when recycling isn't done
holder = new ViewHolder();
convertView.setTag(holder);
}
so we initialize the view-holder & refer all our Views(Buttons, TextViews etc) using findview by id.
the next time getView() is called; it executes this part of the code;
else {
holder = (ViewHolder) convertView.getTag();
}
I'd strongly recommend to first understand working of Android Adapters & List View Recyling Mechanism without using ViewHolders in your code. first you understand how & when the methods are invoked then use ViewHolder for more optimization
I use adapter with ListView this is implementation of getView
#Override
public View getView(int position, View convertView, ViewGroup parent){
ItemViewHolder viewHolder;
if(convertView == null){
convertView = (RelativeLayout)inflater.inflate(resource,parent, false);
viewHolder = new ItemViewHolder();
viewHolder.itemTextName = (TextView)convertView.findViewById(R.id.item_name);
viewHolder.itemTextExpDate = (TextView)convertView.findViewById(R.id.item_exp_date);
viewHolder.itemImage = (ImageView)convertView.findViewById(R.id.item_image);
}
else{
viewHolder = (ItemViewHolder)convertView.getTag();
}
Item item = listItem.get(position);
if(listItem != null){
viewHolder.itemTextName.setText(item.getName());
viewHolder.itemTextExpDate.setText(""+item.getDaysleft());
viewHolder.itemImage.setImageBitmap(item.getImage());
}
return convertView;
}
static class ItemViewHolder {
View baseView;
TextView itemTextName;
TextView itemTextExpDate;
ImageView itemImage;
}
When I set Bitmap to ImageView the ListView is not smooth.
Am I implement the correct code in getView ?
Look on this simple code how you can use Holder pattern simple implementation you must only extern it
On start use Integer.toString or something not
viewHolder.itemTextExpDate.setText(""+item.getDaysleft());
When you use setImage... the getView will be called multiple times.
Why you are checking is it null and 1 line faster you use it ? No sense.
if(listItem != null){
viewHolder.itemTextName.setText(item.getName());
viewHolder.itemTextExpDate.setText(""+item.getDaysleft());
viewHolder.itemImage.setImageBitmap(item.getImage());
}
And the most important thing you don't set holder on the View this code doesn't crash for you?
Look at topics:
Lazy loading
getView called multiple times
getView called multiple times 2
Try adding : convertView.setTag(viewHolder) in the if-block. Also, use a method like Universal Image Loader for loading images in list view
I have list view with custom array adapter. I want to get items click position from getView method. I am getting a few list view items position but when i add more then 7 items into my list i get wrong position from getView method. I mean when i click 9th list item it returns 1.
Here is my code
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
this.position = pos;
Log.v("View position", Integer.toString(pos));
lineView = convertView;
if(lineView==null)
{
adapterLine=new AdapterLine();
layoutInflater=context.getLayoutInflater();
lineView=layoutInflater.inflate(com.inomera.sanalmarket.main.R.layout.adapter, null,true);
adapterLine.sListText = (TextView) lineView.findViewById(R.id.sListText);
adapterLine.sListCheckbox = (CheckBox) lineView.findViewById(R.id.sListCheckbox);
adapterLine.sListImageView = (ImageView) lineView.findViewById(R.id.imageView1);
adapterLine.gestureOverlayView = (GestureOverlayView) lineView.findViewById(com.inomera.sanalmarket.main.R.id.gestureOverlayView1);
adapterLine.gestureOverlayView.setGestureVisible(false);
// To remember whitch tab is selected
adapterLine.sListImageView.setTag(pos);
adapterLine.sListCheckbox.setTag(pos);
adapterLine.sListText.setTag(pos);
Log.v("adapter", "position of adapter is " + Integer.toString(pos));
Thanks for any help!
The array adapter will only create one object per visible row in your list view. After this, the adapter will recycle that already created view. This is the purpose of the:
if(lineView==null)
line in your adapter.
You will want to put in an else section that sets up the row using the recycled view. This other article may be helpful:
How can I make my ArrayAdapter follow the ViewHolder pattern?
This implementation is incomplete add else section which sets value from data. here is implementation which worked for me
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflator = reportViewContext.getLayoutInflater();
convertView = inflator.inflate(R.layout.tabitems, null);
viewHolder.name= (TextView) convertView
.findViewById(R.id.user_reportTab_userName);
//set other values needed in viewHolder if any
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}
//data is list of Data model
if(data.size()<=0) {
//if data unavailable }
else {
/***** Get each Model object from Array list ********/
System.out.println("Position:"+position);
/************ Set Model values in Holder elements ***********/
viewHolder.name.setText(data.get(position).getName());
}
return convertView;
}
I know the question is very old, answered in case anyone stumbled on similar problem
Hallo all,
I have a ListView which contains a Button in each line. The following code is part of the getView() Method
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
TextView tv;
Button saveA_button;
EditText edittext;
FITB_ViewWrapper wrapper;
if (row == null) {
LayoutInflater li = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (ChooseMode_Act.modeInfo.equalsIgnoreCase("Training")) {
row = li.inflate(R.layout.exercise_for_training_fitb,parent, false);
}else {
row = li.inflate(R.layout.exercise_for_exam_fitb,parent, false);
}
wrapper=new FITB_ViewWrapper(row);
row.setTag(wrapper);
if (ChooseMode_Act.modeInfo.equalsIgnoreCase("Exam")) {
saveA_button=wrapper.getSaveAnswer_Button();
OnClickListener l=new OnClickListener() {
#Override
public void onClick(View v) {
Integer mp=(Integer)v.getTag();
Log.i("mp","my Position is: "+mp);
}
};
saveA_button.setOnClickListener(l);
}
}else {
wrapper=(FITB_ViewWrapper) row.getTag();
}
For my App i need to known to which item the Button belongs to, so i try to detect it. The code
Log.i("mp","my Position is: "+mp);
puts out a message: mp myPosition is: null
I can't understand, why do i get a "null" but not an Integer? How can i find out the Position of an Item in a ListView?
Thanks a lot.
Log.i("mp","my Position is: "+position);
you have the position already !
public View getView(final int position, View convertView, ViewGroup parent) {
The Views in a ListView are reused as you scroll up and down. Thus, setting values in getView often has unintented consequences, like the image that you meant to set for item number 5 appearing in item number 10, 15 and 20 also.
To avoid this, if you want to set properties in getView you need to make sure you set or unset them for each view.
I'm not sure what exactly you are trying to accomplish with your code, but it might help to move the setTag outside of the if statement, to make sure you are setting it each time that a view is used.