setImageResource() while using view holder pattern with listview - android

I have a custom base adapter for my listview which I use view holder pattern. I have to change the source of several images dynamically. But when I change one of the images, after a couple of scroll whole images are changing. If I just remove the view holder pattern everything is just fine.
I searched some questions like: Facing critical issue: Toggle image source inside Listview using ViewHolder Pattern
But I couldn't find a proper way to do both.
Here is my getview() function.
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// if (convertView == null) {
holder = new ViewHolder();
convertView = this.inflater.inflate(R.layout.list_row2, parent, false);
// For every single item placed on XML
// Holder must be updated here
holder.codeName = (TextView) convertView.findViewById(R.id.codeName);
holder.level = (TextView) convertView.findViewById(R.id.level);
holder.pt1 = (TextView) convertView.findViewById(R.id.pt1Value);
holder.pt2 = (TextView) convertView.findViewById(R.id.pt2Value);
holder.tt3 = (TextView) convertView.findViewById(R.id.tt3Value);
holder.tt4 = (TextView) convertView.findViewById(R.id.tt4Value);
holder.lastUpdate = (TextView) convertView.findViewById(R.id.lastUpdate);
holder.status = (ImageView) convertView.findViewById(R.id.status);
convertView.setTag(holder);
// }
// else {
// holder = (ViewHolder) convertView.getTag();
// }
// Formatting level
SingleSystem temp = sys.get(position);
temp.seq1 = temp.seq1.replace("," , ".");
Float tempLevel = Float.parseFloat(temp.seq1);
Integer level = Math.round(tempLevel);
//Check if there is an alert on system
if(temp.seq13.contains("1") || temp.seq14.contains("1") ||
temp.seq16.contains("1") || temp.seq30.contains("1") || temp.seq31.contains("1") || temp.seq32.contains("1") ||
temp.seq45.contains("1") )
{
holder.status.setImageResource(R.drawable.process_warning); //If an alert, change running picture
}
//Set background color according to level
if(level<=15){
holder.level.setBackgroundColor(Color.rgb(255,17,0));
holder.status.setImageResource(R.drawable.offline);
}
else if(level>15 && level <30){
holder.level.setBackgroundColor(Color.rgb(255,128,0));
}
else{
holder.level.setBackgroundColor(Color.rgb(66,213,4));
}
// Check Time Out
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
try {
Date serverTime = dateFormat.parse(temp.serverTime);
Date communicationTime = dateFormat.parse(temp.communicationDate);
long diff = serverTime.getTime() - communicationTime.getTime();
diff = diff/1000;
diff = diff/60;
Integer cOut = Integer.parseInt(temp.communicationTimeOut);
if(diff > cOut){
holder.status.setImageResource(R.drawable.offline);
}
}
catch (Exception e){
e.printStackTrace();
}
return convertView;
}
As I said if I remove the if(convertView == null) part, everything is okey. For now I just have 16 rows but it may increase. Will it be big performance issue in the future ? How can I change my code to use view holder pattern ?
Thanks for your answer.

The views are reused, ie. they have all values/colors/drawables from when they were displayed before. You need to reset the image's drawable when reusing the view:
else {
holder = (ViewHolder) convertView.getTag();
holder.status.setImageDrawable(null);
}

Related

How to change color of textView in android listView on comparing JSON data?

I am fetching JSON Data to listView successfully, but i want to change the color of the textView in that listView by comparing JSON data.
For ex-
if in JSON {"status":"approved"} - green color
else if {"status" : "disapproved"} - red color
I'm able to change it using getView in SimpleAdapter but not able to compare strings there.
when i print the status, its is only showing "approved".
i can't filter "disapproved" in else if condition.
SimpleAdapter adapter = new SimpleAdapter(getActivity(), mylist, R.layout.list_leave_approval,
new String[]{
TAG_STATUS
},
new int[]{
R.id.status}) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//return super.getView(position, convertView, parent);
View v = convertView;
if (v == null) {
// View v = convertView;
LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_leave_approval, null);
TextView test = (TextView) v.findViewById(R.id.status);
// String str = jsonObject.getString("status");
Log.d("Day", "get view STATUS: " + strStatus);
// jsonObject = jsonArray.getJSONObject(i);
if (strStatus.equals(" Approved ")) {
test.setBackgroundColor(getResources().getColor(R.color.green));
// txtStatus.setText("DEC");
} else if (strStatus.equals(" Disapproved ")) {
test.setBackgroundColor(getResources().getColor(android.R.color.holo_red_light));
}
}
return super.
getView(position, v, parent);
}
};
list.setAdapter(adapter);
You can do like this.
Here string will be your parsed json string.
JSONObject jObj = new JSONObject(String);
if (jObj.getString("status").equalsIgnoreCase("approved")) {
textView1.setTextColor(Color.GREEN)
} else {
textView1.setTextColor(Color.RED)
}
I advise you to read about MVC design pattern
You should keep your JSON in a data object (model in MVC) for example Status object and put all the needed data from json to this object
When filling the listView adjust the view according to the statuses:
if(items[index].getStatus.equals("approved"))
textView.setTextColor(ContextCompat.getColor(context, R.color.green));
else if(items[index].getStatus.equals("disapproved"))
textView.setTextColor(ContextCompat.getColor(context, R.color.red));
You will need to override a more complex type of Adapter in order to do what you want, SimpleAdapter only allows setting the text in a very simple way as a String.
Something like ArrayAdapter might be a better fit, in that case you could use the code Michael A has shown in the getView method of ArrayAdapter to change the display of the text.
You might also look into SpannableString which allows adding color to text, but this would require being able to provide code to determine the status of the item.

Picasso Only Loading 5 Images until re-using ones in cache

I'm fairly new to android programming. I've run into some issues loading images (bitmaps) into a ListView. It works flawlessly until I have around 5 images loaded, then it reuses the first image I loaded (assuming from cache). I've tried a lot of solutions and bitmap samplings but, still no luck. Here is my code:
#Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = getLayoutInflater().inflate(R.layout.listview_item, parent, false);
Contact currentContact = Contacts.get(position);
TextView name = (TextView) view.findViewById(R.id.contactName);
name.setText(currentContact.getName());
TextView phone = (TextView) view.findViewById(R.id.phoneNumber);
phone.setText(currentContact.getPhone());
TextView email = (TextView) view.findViewById(R.id.email);
email.setText(currentContact.getEmail());
TextView address = (TextView) view.findViewById(R.id.cAddress);
address.setText(currentContact.getAddress());
Context mContext = getApplicationContext();
File file = mContext.getDir("imageDir", Context.MODE_PRIVATE);
String path = "file:" + file.getPath() + "/" + currentContact.getImage() + ".png";
ImageView contactListImage = (ImageView) view.findViewById(R.id.contactListImage);
Picasso.with(getApplicationContext())
.load(path)
.centerInside()
.fit()
.error(R.drawable.user_2)
.into(contactListImage)
}
return view;
}
I did try using
recycleMemoryCache()
Thank in you advance!
You're not using the recycled view correctly.
The view parameter you have there is either null, which means you have to inflate a new one, or not null, which means you should re-use it - assign new values to all the fields etc.
You simply need to move the closing curly-brace above return view; to just after your view inflation:
if (view == null) {
view = getLayoutInflater().inflate(R.layout.listview_item, parent, false);
}
As an aside, I'd look up the viewholder pattern - or just start using RecyclerView, as that enforces it (and is the way of the future for lists on Android).

Android ListView: load items only on scroll

I have a custom adapter for a list view. It has 3 fields: a thumbnail and two text fields.
Once the layout is inflated, the thumbnails are downloaded from an external server.
How do i change the functionality so that the images are downloaded only when the user scrolls down.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Inflate the layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_single, parent, false);
ImageView image = (ImageView) rowView.findViewById(R.id.picture);
TextView firstline = (TextView) rowView.findViewById(R.id.firstline);
TextView secondline = (TextView) rowView.findViewById(R.id.secondline);
// Get information about the report
AnimalLocationLog current = objects.get(position);
// Get all the important information
String species = current.getSpecies();
String sanitizedSpecies = MiscHelpers.sanitizeString(species);
int reportId = objects.get(position).getTrackerId();
// Construct the URL to the image
String imageLocation = websiteUrl + sanitizedSpecies + separator + reportId + extension;
// Display user report
downloader.download(imageLocation, image);
firstline.setText(species);
secondline.setText("Spotted " + current.getDateTime().toString("yyyy-MM-dd H:m"));
return rowView;
}
Add an OnScrollListener to your ListView with ListView.setOnScrollListener() and do the download in the ScrollListener.onScroll() method. You can use the ListView.getLastVisiblePosition() to figure out what list items are visible and which aren't.

getView() is not working as i supposed

I am going to develop a APP where i am using customize alert dialog. Data have come from database to this alert-dialog.
menu_to_showdialogCursor = dh.rawQuery("SELECT _id ,item_name,Item_cost FROM order_customer WHERE item_name LIKE ? AND Item_cost LIKE ?", new String[]{"%","%"});
OrderListAdapter orderAdapter = new OrderListAdapter(MainScreen.this,menu_to_showdialogCursor );
orderList.setAdapter(orderAdapter);
ABove line is calling my Adapter class.Now i ma going to show my getView() in adapter class
public View getView(int position, View convertView, ViewGroup parent) {
OrderViewHolder orderViewHolder = null;
if (convertView == null) {
orderViewHolder = new OrderViewHolder();
convertView = inflater.inflate(R.layout.order_list_row, null);
orderViewHolder.setTvTitle((TextView) convertView
.findViewById(R.id.orderTitle));
orderViewHolder.setTvPrice((TextView) convertView
.findViewById(R.id.orderPrice));
orderViewHolder.setIvDelete((ImageButton) convertView
.findViewById(R.id.deleteOrder));
convertView.setTag(orderViewHolder);
} else {
orderViewHolder = (OrderViewHolder) convertView.getTag();
}
if (position != 0)
{
System.out.println(" value of position :"+position);
List lit = new ArrayList();
List litp = new ArrayList();
// System.out.println(" value of postion of cursor : ");
OrderViewHolder odr_obj = null;
if (oStarterCursor.moveToFirst()) {
do{
odr_obj = new OrderViewHolder();
title = oStarterCursor.getString(oStarterCursor.getColumnIndex("item_name"));
System.out.println("value of title :"+title);
lit.add(title);
price = oStarterCursor.getString(oStarterCursor.getColumnIndex("Item_cost"));
System.out.println("value of price :"+price);
litp.add(price);
}while(oStarterCursor.moveToNext());
}
// _id = oStarterCursor.getInt(oStarterCursor.getColumnIndex("_id"));
if (title != null) {
title = title.trim();
Iterator it = lit.iterator();
while (it.hasNext()) {
int i =0;
//System.out.println(" data iterator "+it.next().toString());
String test =it.next().toString();
System.out.println(" iterator vavue :"+test);
orderViewHolder.getTvTitle().setText(test);
}
orderViewHolder.getTvTitle().setTextColor(R.color.black);
orderViewHolder.getTvTitle().setTextSize(12);
orderViewHolder.getTvTitle().setTypeface(Typeface.DEFAULT);
orderViewHolder.getTvTitle().setGravity(
Gravity.CENTER_VERTICAL);
}
if (price != null) {
price = price.trim();
orderViewHolder.getTvPrice().setText(price + ".00");
orderViewHolder.getTvTitle().setTextColor(R.color.black);
orderViewHolder.getTvTitle().setTextSize(12);
orderViewHolder.getTvTitle().setTypeface(Typeface.DEFAULT);
orderViewHolder.getTvTitle().setGravity(
Gravity.CENTER_VERTICAL);
}
//_id = oStarterCursor.getInt(oStarterCursor.getColumnIndex("_id"));
//convertView.setTag(R.id.orderTitle, _id);
if (orderViewHolder.getIvDelete() != null) {
//orderViewHolder.getIvDelete().setTag(R.id.orderTitle, _id);
}
}
return convertView;}
Problem is that in my data base there is two row as in below image..
But in my alert dialog only showing one row twice. I did not get where is logical mistake.For conveniences i am going to show my screen-shot
So Where is problem i can't get please some body help me take out of this problem.
I think it's your line :
if (position != 0)
The first line of an adapter is 0 so it will not set the data for the first line of data.
I believe its because you are using getView wrong, getView does not just get called once it gets called many times. you are looping through your cursor each time getView is called so you are only displaying the last item in the cursor after you loop through your 2 lists.
if you are getting data from a cursor you should be using SimpleCursorAdapter and then override bindView and just use the cursor variable in the method each time its called
Edit
basically along the lines of this
oStarterCursor.moveToPosition(position);
orderViewHolder.getTvTitle().setText(oStarterCursor.getString(oStarterCursor.getColumnIndex("item_name")));
is all you need to get the data really

Custom ListView Items repeated

I am trying to add dynamic textview to listview items.textviews can be of 1-2 or more than that depending on data I have succeed in adding the textview but problem is textviews are repeated on scroll.
I am creating new object of textview each time in loop.I am aware of the problem that android tries to reuse existing view but i have to add new view every time.
Here is my code in custom adapter:
public class ViewHolder {
TextView text1;
LinearLayout linearLayout;
TextView t;
TextView t1;
}
getView method
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.two_item_icon_text, null);
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.linearLayout = (LinearLayout) convertView.findViewById(R.id.lin_lay_dynamic);
holder.text1.setText("" + DATA1[position]);
String tmp, dateparsed;
dateparsed = DATA1[position].substring(0, DATA1[position].indexOf(":"));
for (int x = 0; x < calendareventholder1.size(); x++) {
objHolder = (CalendarEventHolder) calendareventholder1.get(x);
if (objHolder.opendate.equals(displaydate[current])) {
tmp = objHolder.dtstarttime.toString().substring(0, objHolder.dtstarttime.toString().indexOf(":"));
if (Integer.parseInt(tmp) >= Integer.parseInt(dateparsed) && Integer.parseInt(tmp) < Integer.parseInt(dateparsed) + 1) {
holder.t = new TextView(convertView.getContext());
holder.t.setText(":-d ");
holder.t.setOnClickListener(this);
if (Common.isChildSessionAlerted(String.valueOf(objHolder.id), getApplicationContext(), object1)) {
holder.t.setText(holder.t.getText() + objHolder.dtstarttime + " " + objHolder.dtendtime + " :-a");
} else {
holder.t.setText(holder.t.getText() + objHolder.dtstarttime + " " + objHolder.dtendtime);
}
holder.t.setTag(objHolder.id);
holder.t.setTextSize(Common.getPreferenceInt(getApplicationContext(), Common.PREF_FONT_SIZE, 10));
holder.t.setTextColor(Color.BLACK);
holder.t.setText(getSmiledText(ScheduleActivity.this,
holder.t.getText().toString()));
holder.linearLayout.addView(holder.t);
holder.t1 = new TextView(convertView.getContext());
holder.t1.setOnClickListener(this);
holder.t1.setText(objHolder.title);
holder.t1.setTag(objHolder.id);
holder.t1.setTextSize(Common.getPreferenceInt(getApplicationContext(), Common.PREF_FONT_SIZE, 10));
holder.t1.setTextColor(Color.BLACK);
holder.linearLayout.addView(holder.t1);
}
}
}
return convertView;
}
Its a little hard to really understand what is in holder since it isn't super descriptive, but if I am reading your question right, the reason you are getting repeated items is because you are just adding Views and never deleting what was there before. ListView recycles views, meaning what was there previously stays there. As it scrolls it actually keeps reusing views rather than creating new ones. I won't go into detail because there are a bunch of question on here with similar problems. But at the top you should do
getView() {
/*previous stuff, and holder.linearLayout must have been set!*/
if(holder.linearLayout.getChildCount() > 0)
holder.linearLayout.removeAllViews();
This way any views already there will be removed. One last thing, you should also check out this. Immensely helpful in understanding why you have to do what I posted.

Categories

Resources