Scrolling ListView populates dummy values - android

My listview contains one image,and some textview; there are two textiview which contains the price and special price,if special price is 0 than set only price textview and special price let it null,but special price is > 0 than set price value as well special price,fisrt time everything is going good but when i am scrolling the listview then blank textview set with dumyy valueenter code here
Here is my getView method code.
#Override
public View getView(final int position, View convertView, ViewGroup parent){
//public View getView(int position, View convertView, ViewGroup parent) {
/*View vi = convertView;
if (convertView == null)
{
vi = inflater.inflate(R.layout.list_row, null);
}
*/
int pos=position;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_row, null);
viewHolder=new ViewHolder();
viewHolder.txt_id = (TextView) convertView.findViewById(R.id.id); // title
viewHolder.txt_product_name = (TextView) convertView.findViewById(R.id.title); // title
viewHolder.artist = (TextView) convertView.findViewById(R.id.artist); // artist
// name
viewHolder.txt_mspecialprice_withouttax = (TextView) convertView.findViewById(R.id.duration); // duration
viewHolder.stock = (TextView) convertView.findViewById(R.id.stck);
viewHolder.txt_mprice_withouttax = (TextView) convertView.findViewById(R.id.txtmpricewithouttax);
viewHolder.thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb
// image
convertView.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) convertView.getTag();
}
HashMap<String, String> song = new HashMap<String, String>();
song = data.get(position);
// Setting all values in listview
String mspecialprice_str=song.get(CustomizedListView.KEY_PRODUCT_MSPECIAL_WITHOUT_TAX);
//String substr_mspecialprice_str=mspecialprice_str.substring(1,mspecialprice_str.indexOf("."));
//String substr_mspecialprice_str_replaced=substr_mspecialprice_str.replace(",", "");
String msaleprice_str=song.get(CustomizedListView.KEY_PRODUCT_MPRICE_WITHOUT_TAX);
//String substr_msaleprice_str=msaleprice_str.substring(0,msaleprice_str.indexOf("."));
//String substr_msaleprice_str_replaced=substr_msaleprice_str.replace(",", "");
viewHolder.txt_id.setText(song.get(CustomizedListView.KEY_PRODUCT_ID));
viewHolder.txt_product_name.setText(song.get(CustomizedListView.KEY_PRODUCT_NAME));
viewHolder.artist.setText(song.get(CustomizedListView.KEY_PRODUCT_DESCRIPTION));
viewHolder.stock.setText(song.get(CustomizedListView.KEY_STOCK));
if(mspecialprice_str.equals("0"))
{
//txt_mspecialprice_withouttax.setText(song.get(CustomizedListView.KEY_PRODUCT_MSPECIAL_WITHOUT_TAX));
viewHolder.txt_mprice_withouttax.setText("$"+(song.get(CustomizedListView.KEY_PRODUCT_MPRICE_WITHOUT_TAX)));
viewHolder.txt_mprice_withouttax.setTextColor(Color.parseColor("#64aef9"));
}
//if(!(mspecialprice_str.equals("0")))
//{
else
{
viewHolder.txt_mspecialprice_withouttax.setText("$"+(song.get(CustomizedListView.KEY_PRODUCT_MSPECIAL_WITHOUT_TAX)));
viewHolder.txt_mprice_withouttax.setText("$"+(song.get(CustomizedListView.KEY_PRODUCT_MPRICE_WITHOUT_TAX)));
viewHolder.txt_mprice_withouttax.setPaintFlags(viewHolder.txt_mprice_withouttax.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
viewHolder.txt_mprice_withouttax.setTextColor(Color.parseColor("#F01616"));
}
imageLoader.DisplayImage(
song.get(CustomizedListView.KEY_PRODUCT_IMAGEURL), viewHolder.thumb_image);
return convertView;
}
}
class ViewHolder {
TextView txt_id ; // title
TextView txt_product_name; // title
TextView artist ; // artist
// name
TextView txt_mspecialprice_withouttax; // duration
TextView stock ;
TextView txt_mprice_withouttax;
ImageView thumb_image ; // thumb
}

ListView, GridView reuse views used as list items/grid elements. getView() is called everytime android tries to draw next element while scrolling your view. There is no need to prevent that!
Edit - Atrix1987
From the developer docs
An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set.
Suppose you have 10 elements which you want to show using your GridView/ListView and the maximum visible items is 5 then the same 5 views can be reused to display the rest of the 5 elements when you scroll. This is the intended behavior and is the right way to do things [keeps number of views to a minimum].
You don't have control on getView method, the framework does that for you.

The GridView widget extends AdapterView. It uses the adapter to allow the reuse of Views and improve performance. There is no way to avoid calling getView() - it is essential to the whole AdapterView idea. If you want a static layout, perhaps you should use something else.

Related

Change Listview item background

As Adapter for ListView, I am using custom adapter. On Adapter's getView method, I am trying to change listitem's background image using setBackgroundDrawable.
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
CurrencyModel currency = new CurrencyModel();
currency = currencyList.get(position);
if (convertView == null) {
vi = inflater.inflate(R.layout.listitem_currency, null);
}
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
TextView tvSize = (TextView) vi.findViewById(R.id.tvSize);
TextView tvName = (TextView) vi.findViewById(R.id.tvName);
TextView tvRate = (TextView) vi.findViewById(R.id.tvRate);
tvSymbol.setText(currency.getSymbol());
tvSize.setText(currency.getSize());
tvName.setText(currency.getName());
tvRate.setText(currency.getRate());
if (currency.getSymbol().equals("AUD")) {
vi.setBackgroundDrawable(context.getResources().getDrawable(
R.drawable.bg_exch_high_cell));
}
return vi;
}
When activity starts, everything is working correctly - listitem with AUD has different background. All mystery starts when I scroll the listview - other listitems also get "special" background. The more scroll, the more listitems changed. I do not have idea why this is happening. How to solve this problem?
if (currency.getSymbol().equals("AUD")) {
vi.setBackgroundDrawable(context.getResources().getDrawable(
R.drawable.bg_exch_high_cell));
}
else {//restore default background}
This happens because cell views are reused by listview. You should restore default background for other items.
More about list view performance
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
Before this line add the default background the you put to the item. The reason in your code why it happens is that android try using the the already created view(vi). Since if it is assigned bg_exch_high_cell, it will retain it. So reset it in the beginning.
vi.setBackgroundDrawable(context.getResources().getDrawable(
//default background drawable here ));
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);

How this code works?

I've written this code from a tutorial.
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.single_row, viewGroup,false);
TextView title = (TextView) row.findViewById(R.id.txtTitle);
TextView description = (TextView) row.findViewById(R.id.txtDescription);
ImageView image = (ImageView) row.findViewById(R.id.imgPic);
SingleRow temp = list.get(i);
title.setText(temp.title);
description.setText(temp.description);
image.setImageResource(temp.image);
return row;
}
In this line of code:
TextView title = (TextView) row.findViewById(R.id.txtTitle);
I think a TextView is copied to a variable of the same kind. and then in this line of code:
title.setText(temp.title);
we fill that variable with something. then the row variable which is a View and it's not related to 'title' variable is returned.
How it works? I thinks these variables have nothing to do here.
This code inflates a new view, settings it's contents. This means that you're creating a new view programatically. It's often used i.e. when populating a list, where you'll have number of rows, each identical in structure, but with different values.
Here is how it works:
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
// Get the inflater service
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Inflate view with ID = R.layout.single_row into the row variable
View row = inflater.inflate(R.layout.single_row, viewGroup,false);
// Get child views of row: title, description and image.
TextView title = (TextView) row.findViewById(R.id.txtTitle);
TextView description = (TextView) row.findViewById(R.id.txtDescription);
ImageView image = (ImageView) row.findViewById(R.id.imgPic);
// This get's some template view which will provide data: title, description and image
SingleRow temp = list.get(i);
// Here you're setting title, description and image by using values from `temp`.
title.setText(temp.title);
description.setText(temp.description);
image.setImageResource(temp.image);
// Return the view with all values set. This view will be later probably added somewhere as a child (maybe into a list?)
return row;
}
That's the method used to return the view for a row in the listview. row variable is actually related to title, as you can see here.-
TextView title = (TextView) row.findViewById(R.id.txtTitle);
in other words, title is a TextView inside row object, and that code retrieves it to set its text. To sum up, the whole getView method is inflating a single_row View, and setting properties for all relevant children of row.
View row = inflater.inflate(R.layout.single_row, viewGroup,false);
You are inflating a layout single_row
TextView title = (TextView) row.findViewById(R.id.txtTitle);
Initializing textview which is in singlerow.xml
title.setText(temp.title);
Setting title to textview.
You are infalting a layout for each row in listview.
Also it is better to use a viewHolder pattern.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
Also you can move the below to the constructor of adapter class and declare inflater as a class member
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
The below link may be of interest to you
How ListView's recycling mechanism works

ListView item style keeps changing randomly when there are multiple style in the same ListView

I have made a chat application where the chat view is formed from many rows in a ListView where messages sent by the user are displaying in white and messages received by friend are displayed in blue.
This behavior works fine, but when I scroll the list after becoming really big (e.g. 30 rows) the colors are messed. I use different layouts for each row, white row layout and blue row layout.
When I scroll multiple times up and down the list the colors keeps switching randomly (i.e. some of my messages are in blue and others in white, and some of the other end (the friend chatting with me) becomes white and other messages become blue in a random way.
I'll give you a snipped preview on the code used:
This is the getView method in my custom adapter which extends BaseAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final int pos = position;
String from = messages.get(pos).getFrom();
if (convertView == null) {
holder = new ViewHolder();
// If message is sent by me (the user)
if(from.toString().toLowerCase().equals("me")){
convertView = mInflater.inflate(R.layout.chat_msg_row2, null);
}
// if message is sent by his friend (the other end user)
else{
convertView = mInflater.inflate(R.layout.chat_msg_row, null);
}
holder.userName = (TextView) convertView.findViewById(R.id.msgusername);
holder.userImage = (ImageView) convertView.findViewById(R.id.ppic);
holder.date = (TextView) convertView.findViewById(R.id.msgdate);
holder.text = (TextView) convertView.findViewById(R.id.msg);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.userName.setText( messages.get(pos).getFrom() );
holder.text.setText( messages.get(pos).getText() );
holder.date.setText( messages.get(pos).getDate() );
String img = messages.get(pos).getImage();
if(img.substring(0,4).equalsIgnoreCase("http") ){
try{
ImageLoader imloader = new ImageLoader( ChatActivity.this );
holder.userImage.setTag(img);
imloader.DisplayImage( img, ChatActivity.this , holder.userImage );
}
catch(Exception e){
e.printStackTrace();
}
}
return convertView;
}
public long getItemId(int position){
return 1;
}
public class ViewHolder{
TextView userName;
ImageView userImage;
TextView text;
TextView date;
}
The two layouts, chat_msg_row2 and chat_msg_row, are identical except for the Drawable used, where one is using a white image and the other using a blue image.
I recently faced similar problem. What I did was remove the
if (convertView == null)
and the return the View itself. What that above code does is : it checks if there are previous cache present in the present list. If present it re-uses previously present list. Hope it helps
As you didn't use the getItemViewType and the getViewTypeCount methods of the adapter, then the ListView will assume you only have one type of row(although you actually use two types) and will recycle rows as they appear in the list. So, when the convertView is not null you get a recycled row that could be either one of those two types depending on its position.
But the methods above should be implemented only if your rows are really different(extra widgets, placement rules etc). If your two rows are different only by the background image then you need only one row and you'll be setting the background based on your app's logic, something like this:
//...
if (convertView == null) {
holder = new ViewHolder();
// just inflate one of the rows if they are identical
convertView = mInflater.inflate(R.layout.chat_msg_row, parent, false);
holder.userName = (TextView) convertView.findViewById(R.id.msgusername);
holder.userImage = (ImageView) convertView.findViewById(R.id.ppic);
holder.date = (TextView) convertView.findViewById(R.id.msgdate);
holder.text = (TextView) convertView.findViewById(R.id.msg);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// set the background image as desired
if(from.toString().toLowerCase().equals("me")){
// I assumed you set the background on the root of the View row, convertView
// otherwise search for the desired view in convertView and set the background
convertView.setBackgroundResource(R.drawable.the_me_background_drawable);
} else {
convertView.setBackgroundResource(R.drawable.the_other_user_background_drawable);
}
// ...

Weird behavior in ListView GetView() method position

I've a custom adapter for my ListView where I send to it a List, and if the position is in the list then the imageview (that is in the custom row) change its src to another.. Here is the GetView method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.start_row, null); // line
// 47
holder = new ViewHolder();
holder.tv_SuraName = (TextView) convertView.findViewById(R.id.Start_Name);
holder.tv_SuraName.setTypeface(Font);
holder.tv_PageNumber = (TextView) convertView.findViewById(R.id.Start_Numbering);
holder.im_Audio = (ImageView) convertView.findViewById(R.id.Start_ImageView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tv_SuraName.setText(SuraList_SuraNamesCode[position]);
holder.tv_PageNumber.setText(Integer.toString(PageNumber[position]));
holder.im_Audio.setOnClickListener(new imageViewClickListener(position));
if (TilawaAvailable.contains(position))
holder.im_Audio.setImageResource(R.drawable.quran_list_audioavailable);
return convertView;
}
I send a List with 1 position.If I scroll the ListView slowly, this works good and only 1 imageview gets changed as it should be. But if I scroll fast, other imagesviews that are close to the correct position also gets changed!
Can anyone tell me why?
You don't ever set the imageResource to something else if position isn't contained in your list. When the view with the custom image leaves the screen it is probably getting placed at a lower position in the list and getting reused.
Try changing this:
if (TilawaAvailable.contains(position))
holder.im_Audio.setImageResource(R.drawable.quran_list_audioavailable);
To this:
if (TilawaAvailable.contains(position))
holder.im_Audio.setImageResource(R.drawable.quran_list_audioavailable);
else
holder.im_audio.setImageResource(r.drawable.SOME_THING_ELSE);

how to change listview's row properties without layout?

Good time!
My Android app has so feature that I use ListView in the one of the page of TabHost without layout for ListView. Like that:
ListView lv = new ListView(this);
lv.setAdapter(myAdapter);
So I'd like to change some row's properties like text size in the row. So, how can I get access to the properties of the explicit row of ListView to change text size, for example?
Use BaseAdapter and modify font size in getView call.
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_layout, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Change text size
holder.text.setTextAppearance(context,R.style.customStyle);
return convertView;
}
static class ViewHolder {
TextView text;
}
And you can use position variable in getView call to change specific row. Hope this help!!!

Categories

Resources