My custom listview adapter repeats the last item - java

The code below repeats the last element 4 times. This ListView is used in a tabbed activity fragment. I searched on the internet but found nothing helpful. Please help!
My adapter class:
public class MyAdapter extends ArrayAdapter<ElementList> {
public MyAdapter(Context context, ArrayList<ElementList> EventList){
super(context,0,EventList);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent){
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_adapter, parent, false);
holder = new ViewHolder();
holder.id = (TextView) convertView.findViewById(R.id.textView9);
holder.name = (TextView) convertView.findViewById(R.id.textView6);
holder.date =(TextView)convertView.findViewById(R.id.textView7);
holder.time =(TextView)convertView.findViewById(R.id.textView8);
convertView.setTag( holder );
} else {
holder = (ViewHolder) convertView.getTag();
}
ElementList elementList = getItem(position);
if(elementList != null) {
holder.id.setText(ElementList.id);
holder.name.setText(ElementList.name);
holder.date.setText(ElementList.date);
holder.time.setText(ElementList.time);
}
return convertView;
}
Usage of that ListView:
ArrayList<ElementList> EventList = new ArrayList<ElementList>();
EventList.add( new ElementList("1","bla1","12/34/45","12:40"));
EventList.add( new ElementList("1","bla2","12/34/45","12:40"));
EventList.add( new ElementList("1","bla3","12/34/45","12:40"));
EventList.add( new ElementList("1","bla4","12/34/45","12:40"));
MyAdapter adapter = new MyAdapter(getActivity(),EventList);
ListView myList = (ListView) rootView.findViewById(R.id.listView);
myList.setAdapter(adapter);
Any suggestions ? .

I think this
if(elementList != null) {
holder.id.setText(ElementList.id);
holder.name.setText(ElementList.name);
holder.date.setText(ElementList.date);
holder.time.setText(ElementList.time);
}
should be this
if(elementList != null) {
holder.id.setText(elementList.id);
holder.name.setText(elementList.name);
holder.date.setText(elementList.date);
holder.time.setText(elementList.time);
}
I don't know if this will help, though. You can add in some log statements to see what's actually in your arrayList right after you populate it as well as when the adapter is getting ready to read from it.

Related

Android ListView getView display image randomly

I would like to display items with an adapter in a ListView but when getView is called in the ArrayAdapter, it displays the good image but not on the good item when I am scrolling. It is like if the findViewById didn't give me the good id of the layout.
public class ItemPackAdapter extends ArrayAdapter<Pack> {
Context context;
public ItemPackAdapter(Context context, ArrayList<Pack> pack) {
super(context, 0, pack);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// Check if an existing view is being reused, otherwise inflate the view
final Pack pack = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_pack, parent, false);
holder = new ViewHolder();
holder.textView1 = (TextView) convertView.findViewById(R.id.textView1);
holder.textView2 = (TextView) convertView.findViewById(R.id.textView2);
holder.textView3 = (TextView) convertView.findViewById(R.id.textView3);
holder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
if (!pack.getImageName().equals("null")) {
UrlGenerator urlGenerator = new UrlGenerator();
String url = urlGenerator.getDownloadPicture(pack.getImageName());
DownloadPicture downloadPicture = new DownloadPicture(holder.imageView, url, getContext());
downloadPicture.start();
}
convertView.setTag(holder);
}
else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView1.setText(pack.getSomething1());
holder.textView2.setText(pack.getSomething2());
holder.textView3.setText(pack.getSomething3());
if (!pack.getImageName().equals("null")) {
UrlGenerator urlGenerator = new UrlGenerator();
String url = urlGenerator.getDownloadPicture(pack.getImageName());
DownloadPicture downloadPicture = new DownloadPicture(holder.imageView, url, getContext());
downloadPicture.start();
}
if(pack.getImageName().equals("null")){
holder.imageView.setImageBitmap(null);
}
return convertView;
}
static class ViewHolder {
TextView textView1;
TextView textView2;
TextView textView3;
ImageView imageView;
}
}
Actually I found a solution with :
if(pack.getImageName().equals("null")){
holder.imageView.setImageBitmap(null);
}
But when I am scrolling on the listView, I can see the image in the wrong item, and I need to scroll again to call getView to delete the image with the previous condition.
I would like something cleaner :p
Thank you in advance.
And sorry for my bad English.
Your code looks will work just fine with just a little tweak. I discovered that you were setting the ImageView twice, so I edit your code as shown below
public class ItemPackAdapter extends ArrayAdapter<Pack> {
Context context;
ArrayList<Pack> packs;
public ItemPackAdapter(Context context, ArrayList<Pack> packs) {
super(context, 0, packs);
this.context = context;
this.packs = packs;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// Check if an existing view is being reused, otherwise inflate the view
final Pack pack = packs.get(position);
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_pack, parent, false);
holder = new ViewHolder();
holder.textView1 = (TextView) convertView.findViewById(R.id.textView1);
holder.textView2 = (TextView) convertView.findViewById(R.id.textView2);
holder.textView3 = (TextView) convertView.findViewById(R.id.textView3);
holder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (pack.getImageName().equals("null")) {
holder.imageView.setImageBitmap(null);
} else {
UrlGenerator urlGenerator = new UrlGenerator();
String url = urlGenerator.getDownloadPicture(pack.getImageName());
DownloadPicture downloadPicture = new DownloadPicture(holder.imageView, url, getContext());
downloadPicture.start();
}
holder.textView1.setText(pack.getSomething1());
holder.textView2.setText(pack.getSomething2());
holder.textView3.setText(pack.getSomething3());
return convertView;
}
static class ViewHolder {
TextView textView1;
TextView textView2;
TextView textView3;
ImageView imageView;
}
}
In this case if you don't caching your image that may give you like this problem.
Use Picasso library is highly recommended for avoiding this problem. Add the picasso library in your project then write your code some thing like this.
Picasso.with(getApplicationContext()).load(url).into(holder.imageView);
instead of this line
DownloadPicture downloadPicture = new DownloadPicture(holder.imageView, url, getContext());
downloadPicture.start();

ArrayAdapter getView returns NullPointerException -

I'm new to android, I've tried many solutions but nothing works!
Can you please see what's wrong with my code:
I get NullPointerException in holder.CardContent.setText(card.getString("content"));
I've tried to change layoutInflater from null to parent, false
The ids are not the false one!
CardAdapter.java
public class CardAdapter extends ArrayAdapter<ParseObject> {
protected Context mContext;
protected List<ParseObject> mCards;
public CardAdapter(Context context, List<ParseObject> cards) {
super(context, R.layout.card_item, cards);
mContext = context;
mCards = cards;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.card_item, null);
holder = new ViewHolder();
holder.CardContent = (TextView) convertView.findViewById(R.id.cardText);
} else{
holder = (ViewHolder) convertView.getTag();
}
ParseObject card = mCards.get(position);
holder.CardContent.setText(card.getString("content")); // <-- NPE here.
return convertView;
}
private static class ViewHolder{
TextView CardContent;
}
}
Logcat:
at com.kardapps.lifehacks.activities.CardAdapter.getView(CardAdapter.java:64)
at android.widget.AbsListView.obtainView(AbsListView.java:2255)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1263)
at android.widget.ListView.onMeasure(ListView.java:1175)
.......
The problem is that holder is null at least for the beginning.
card could be null too but its not clear at the moment.
Although the adapter recycling logic is right you have forgotten to setTag to the View.
The logic of the recycling is that the way you scroll you save (using setTag) the already read/seen data to the view (here convertView).
Then each time you pass the same position you use setTag to retrieve them instead of recreating them (LayoutInflater.from...)
#Override
public View getView(int position, #Nullable View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
// This is not an error but using parent you avoid Lint warnings
convertView = LayoutInflater.from(mContext).inflate(R.layout.card_item, parent);
holder = new ViewHolder();
holder.CardContent = (TextView) convertView.findViewById(R.id.cardText);
convertView.setTag(holder); // <-- As suggested for improvement
} else {
holder = (ViewHolder) convertView.getTag();
}
ParseObject card = mCards.get(position);
holder.CardContent.setText(card.getString("content")); // <-- NPE here.
// convertView.setTag(holder); // <-- This line is missing
return convertView;
}
You need to set convertView's tag to the holder in your if-block.
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.card_item, null);
holder = new ViewHolder();
holder.CardContent = (TextView) convertView.findViewById(R.id.cardText);
// Add this line
convertView.setTag(holder);
}
You can see that in the else-block, you're retrieving the tag and casting it to ViewHolder. If you haven't set the tag, getTag() returns null, causing the Exception.
See this code:
if(convertView == null){
convertView = LayoutInflater.from(mContext).inflate(R.layout.card_item, null);
holder = new ViewHolder();
holder.CardContent = (TextView) convertView.findViewById(R.id.cardText);
}
else{
holder = (ViewHolder) convertView.getTag();
}
ParseObject card = mCards.get(position);
holder.CardContent.setText(card.getString("content"));
Two possibilities:
if convertView is not null, you are just initialising holder object and not cardContent.
mCards.get(position); returns null

ListView displays different items than what is in the holder

I have a custom adapter that extends the baseadapter. It has a variety of different layouts some with thumbnails some without. When I add a new item that is the same type as the one before the row displays the same values. But when I check what is set in the holder it tells me that the correct items are set.
public View getView(int position, View convertView, ViewGroup parent) {
int layoutType = getItemViewType(position);
ListViewRow item = null;
if(convertView == null) {
item = atIndex(position);
holder = new ViewHolder();
convertView = getConvertView(layoutType, parent);//ViewHolder items declared here
convertView.setTag(-1, holder);
}
else if(!viewMatchesType(layoutType, convertView.getId())){
item = atIndex(position);
holder = new ViewHolder();
convertView = getConvertView(layoutType, parent);//ViewHolder items declared here
convertView.setTag(-1, holder);
}
else {
holder = (ViewHolder) convertView.getTag(-1);
item = atIndex(position);
}
setDisplay(item, convertView);//I set values here
if(holder.tv_name.getText() != item.getName()) {
notifyDataSetInvalidated();
}
return convertView;
}
//For performance, ui elements are saved in a holder
private static class ViewHolder {
public ImageView iv_thumbnail;
public TextView tv_name;
}
i havent really found optimal solution for this problem myself, but removing this if condition seems to work for me. Instead of this
if(convertView == null) {
item = atIndex(position);
holder = new ViewHolder();
convertView = getConvertView(layoutType, parent);//ViewHolder items declared here
convertView.setTag(-1, holder);
}
just use this
item = atIndex(position);
holder = new ViewHolder();
convertView = getConvertView(layoutType, parent);//ViewHolder items declared here
convertView.setTag(-1, holder);
it sure is heavy on memory, but i haven't really found any other solution.

Specify color for each listview row

I fill my ListView with this code:
final ListView lv = (ListView) findViewById(R.id.lvKinder);
ArrayList<Kind> kisi = datenfuerlistview();
KinderlistAdapter kiadapter = new KinderlistAdapter(this, kisi);
lv.setAdapter(kiadapter);
final DBHelper db = new DBHelper(this);
Now I want to analyse one entry of every Kind object I add to my ListView. If it has a certain value, I want to change the backgroundcolor for this ListView entry.
HereĀ“s my adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
convertView = inflator.inflate(R.layout.list_black_text, parent, false);
holder = new ViewHolder((TextView) convertView.findViewById(R.id.nullline), (TextView) convertView.findViewById(R.id.firstLine), (ImageView) convertView.findViewById(R.id.imgv));
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
Kind ki = (Kind) getItem(position);
holder.getName().setText(ki.getName());
holder.getDatum().setText(ki.getDatum());
Uri uri = Uri.parse(ki.getGeschlecht());
String path = ki.getKinderbild();
System.out.println("HSSSSSSSSSSSSSSSSSSSSSS" + path);
//holder.getGeschlecht().setImageBitmap(bitmap);
ContentResolver cr = context.getContentResolver();
Bitmap tmp = null;
try {
tmp = getThumbnail(cr, path);
} catch (Exception e) {
System.out.println("NAAAAAAAAAAAAAAAAAAAA") ;
e.printStackTrace();
}
holder.getGeschlecht().setImageBitmap(tmp);
return convertView;
How to set the color?
Did you tried this ? (before returning convertView) :
convertView.setBackgroundColor(Color.BLUE);//or another color

How to get view for an item in listview in android?

Is it possible to get an item view based on its position in the adapter and not in the visible views in the ListView?
I am aware of functions like getChildAt() and getItemIdAtPosition() however they provide information based on the visible views inside ListView. I am also aware that Android recycles views which means that I can only work with the visible views in the ListView.
My objective is to have a universal identifier for each item since I am using CursorAdapter so I don't have to calculate the item's position relative to the visible items.
Here's how I accomplished this. Within my (custom) adapter class:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
LayoutInflater inflater = context.getLayoutInflater();
view = inflater.inflate(textViewResourceId, parent, false);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.name = (TextView) view.findViewById(R.id.name);
viewHolder.button = (ImageButton) view.findViewById(R.id.button);
viewHolder.button.setOnClickListener
(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = (int) viewHolder.button.getTag();
Log.d(TAG, "Position is: " +position);
}
});
view.setTag(viewHolder);
viewHolder.button.setTag(items.get(position));
} else {
view = convertView;
((ViewHolder) view.getTag()).button.setTag(items.get(position));
}
ViewHolder holder = (ViewHolder) view.getTag();
return view;
}
Essentially the trick is to set and retrieve the position index via the setTag and getTag methods. The items variable refers to the ArrayList containing my custom (adapter) objects.
Also see this tutorial for in-depth examples. Let me know if you need me to clarify anything.
See below code:
public static class ViewHolder
{
public TextView nm;
public TextView tnm;
public TextView tr;
public TextView re;
public TextView membercount;
public TextView membernm;
public TextView email;
public TextView phone;
public ImageView ii;
}
class ImageAdapter extends ArrayAdapter<CoordinatorData>
{
private ArrayList<CoordinatorData> items;
public FoodDriveImageLoader imageLoader;
public ImageAdapter(Context context, int textViewResourceId,ArrayList<CoordinatorData> items)
{
super(context, textViewResourceId, items);
this.items = items;
}
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
ViewHolder holder = null;
if (v == null)
{
try
{
holder=new ViewHolder();
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new FoodDriveImageLoader(FoodDriveModule.this);
v = vi.inflate(R.layout.virtual_food_drive_row, null);
//System.out.println("layout is null.......");
holder.nm = (TextView) v.findViewById(R.id.name);
holder.tnm = (TextView) v.findViewById(R.id.teamname);
holder.tr = (TextView) v.findViewById(R.id.target);
holder.re = (TextView) v.findViewById(R.id.received);
holder.membercount = new TextView(FoodDriveModule.this);
holder.membernm = new TextView(FoodDriveModule.this);
holder.email = new TextView(FoodDriveModule.this);
holder.phone = new TextView(FoodDriveModule.this);
holder.ii = (ImageView) v.findViewById(R.id.icon);
v.setTag(holder);
}
catch(Exception e)
{
System.out.println("Excption Caught"+e);
}
}
else
{
holder=(ViewHolder)v.getTag();
}
CoordinatorData co = items.get(position);
holder.nm.setText(co.getName());
holder.tnm.setText(co.getTeamName());
holder.tr.setText(co.getTarget());
holder.re.setText(co.getReceived());
holder.ii.setTag(co.getImage());
imageLoader.DisplayImage(co.getImage(), FoodDriveModule.this , holder.ii);
if (co != null)
{
}
return v;
}
}
A better option is to identify using the data returned by the CursorAdapter rather than visible views.
For example if your data is in a Array , each data item has a unique index.
Here, Its very short described code, you can simple re-use viewholder pattern to increase listview performance
Write below code in your getview() method
ViewHolder holder = new ViewHolder();
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.skateparklist, null);
holder = new ViewHolder();
holder.headlineView = (TextView) convertView
.findViewById(R.id.textView1);
holder.DistanceView = (TextView) convertView
.findViewById(R.id.textView2);
holder.imgview = (NetworkImageView) convertView
.findViewById(R.id.imgSkatepark);
convertView.setTag(holder); //PLEASE PASS HOLDER AS OBJECT PARAM , CAUSE YOU CAN NOY PASS POSITION IT WILL BE CONFLICT Holder and Integer can not cast
//BECAUSE WE NEED TO REUSE CREATED HOLDER
} else {
holder = (ViewHolder) convertView.getTag();
}
// your controls/UI setup
holder.DistanceView.setText(strDistance);
......
return convertview
Listview lv = (ListView) findViewById(R.id.previewlist);
final BaseAdapter adapter = new PreviewAdapter(this, name, age);
confirm.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
View view = null;
String value;
for (int i = 0; i < adapter.getCount(); i++) {
view = adapter.getView(i, view, lv);
Textview et = (TextView) view.findViewById(R.id.passfare);
value=et.getText().toString();
Toast.makeText(getApplicationContext(), value,
Toast.LENGTH_SHORT).show();
}
}
});

Categories