Android | ListView Using Layoutinflater - android

Im Writing An Application that reads XML file and Displays it as a ListView
cause each row has its own Image and Text i am using LayoutInflater, i can display the Texts but cant display Images! this is the code i use for ImageAdapter:
public class ImageAdaptertwo extends ArrayAdapter<String> {
private final Context context;
private final ArrayList<String> values;
private final ArrayList<String> values2;
public ImageAdaptertwo(Context context, ArrayList<String> values,ArrayList<String> values2) {
super(context, R.layout.trimester1_listview, values);
this.context = context;
this.values = values;
this.values2 = values2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String s = values.get(position);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.trimester1_main, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label2);
ImageView imageView = (ImageView) rowView.findViewById(R.id.icon2);
textView.setText(values2.get(position));
// Change icon based on name
//String s = values.get(position);
System.out.println(s);
if (s.equals(" havingsuccessful-pregnancyS.png")) {
imageView.setImageResource(R.drawable.n1);
} else if (s.equals("urfoodguideduringpregnancyS.png")) {
imageView.setImageResource(R.drawable.n2);
} else if (s.equals("lovingurpregnantbodyS.png")) {
imageView.setImageResource(R.drawable.n3);
} else if (s.equals("gettinggoodbreastafterS.png")) {
imageView.setImageResource(R.drawable.n4);
} else if (s.equals("FoodGuidePyramidS.png")) {
imageView.setImageResource(R.drawable.n5);
} else if (s.equals("pregnancyS.png")) {
imageView.setImageResource(R.drawable.n6);
} else if (s.equals("nutritionfoS.png")) {
imageView.setImageResource(R.drawable.n7);
} else if (s.equals("Your-Growing-ChildS.png")) {
imageView.setImageResource(R.drawable.n8);
} else if (s.equals("Fatigue-in-first-trimesterS.png")) {
imageView.setImageResource(R.drawable.n9);
} else if (s.equals("T1S.png")) {
imageView.setImageResource(R.drawable.n10);
}
return rowView;
}
}
values and values2 are the ArrayList which are Coming from XML Parser! Actually no they are ok because i print the content of them and see them in LogCat!
in my Activit i use this for Adapting ImageAdapter
setListAdapter(new ImageAdaptertwo(this, imagelink,texts));
The result is a listview with texts but no Images!
can anybody tell me how i can fix this and display XML contents on ListView?
Solved the problem by changing if Statements to Switch Case . now for each row i have specific number

Well basically a problem in your if - else then. String comparisons are not happening as you expect. Make sure you check any code involving equals,equalsignorecase twice in JAVA. String comparisons are unnecessarily complicated. Also instead of if-else you can use switch and make your life just a little bit easier.
To get images from online you have to get the images on a background thread and then display on the main thread.
See this for help : http://android-developers.blogspot.in/2009/05/painless-threading.html
Similar question: unable to display url image (bitmap)

Solved the problem by changing if Statements to Switch Case . now for each row i have specific image

Related

item images get mixed after listview scrolls down

i have an activity to show user contacts list. if contact exists in my app i want to show a follow button , else i want to show a whatsapp and telegram icon to invite them.
when i open the activity every thing is fine as i want , but when i scroll down and come back up follow buttons and whats app icons get mixed for different contacts ! the users who had follow button may see whatsapp icon or the others may see follow button !
and everytime i scroll down and up again positions will change !
i should say all contacts name and mobile number are fixed and correct ! just images get mixed !
i know the problem is from my getView function but dont know how to fix it :(
how can i fix it ? tnx :)
Here is all of my adapter code :
public class LazyAdapterContactsList extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
public ImageLoader profileImageLoader;
HashMap<String, String> song;
public LazyAdapterContactsList(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
profileImageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
ViewHolder holder = null;
if(vi==null) {
vi = inflater.inflate(R.layout.contacts_list_row, null);
holder = new ViewHolder();
holder.listID = (TextView) vi.findViewById(R.id.MyContactslistIDPosition);
holder.name = (TextView) vi.findViewById(R.id.MyContactslistName);
holder.mobile = (TextView) vi.findViewById(R.id.MyContactslistMobileNumber);
holder.whatsAppIcon = (ImageView) vi.findViewById(R.id.MyContactsListWhatsApp);
holder.telegramIcon = (ImageView) vi.findViewById(R.id.MyContactsListTelegram);
holder.followBtn = (Button) vi.findViewById(R.id.MyContactsListFollowBtn);
holder.linearLayout = (LinearLayout) vi.findViewById(R.id.MyContactsthumbnail);
holder.profile_thumb_image = (ImageView) vi.findViewById(R.id.MyContactslist_image_profilephoto);
vi.setTag(holder);
}
else {
holder = (ViewHolder)vi.getTag();
}
song = data.get(position);
// Setting all values in listview
holder.listID.setText(song.get(MyContacts.KEY_ID));
holder.name.setText(song.get(MyContacts.KEY_NAME));
holder.mobile.setText(song.get(MyContacts.KEY_MOBILE));
if (song.get(MyContacts.KEY_USER_EXISTS).equals("1"))
{
if (song.get(MyContacts.KEY_THUMB_PROFILE_URL).equals("no")) {
} else {
profileImageLoader.DisplayImage(song.get(MyContacts.KEY_THUMB_PROFILE_URL), holder.profile_thumb_image);
}
}else {
holder.linearLayout.setVisibility(View.VISIBLE);
holder.followBtn.setVisibility(View.GONE);
}
return vi;
}
public static class ViewHolder {
public TextView textView ,listID ,name,mobile;
public ImageView whatsAppIcon ,telegramIcon;
public Button followBtn;
public LinearLayout linearLayout;
public ImageView profile_thumb_image;
}
}
Whatever action you do with any view of ListView like HIDE or VISIBLE in condition (if), you must have to set opposite HIDE or VISIBLE in opposite condition (else).
Try this solution just change code as per below:
if (song.get(MyContacts.KEY_USER_EXISTS).equals("1"))
{
holder.linearLayout.setVisibility(View.GONE);
holder.followBtn.setVisibility(View.VISIBLE);
if (song.get(MyContacts.KEY_THUMB_PROFILE_URL).equals("no")) {
} else {
profileImageLoader.DisplayImage(song.get(MyContacts.KEY_THUMB_PROFILE_URL), holder.profile_thumb_image);
}
}else {
holder.linearLayout.setVisibility(View.VISIBLE);
holder.followBtn.setVisibility(View.GONE);
}
Simple answer is, use floatingaction button. The position of the button will remain same, and you wouldn't feel annoyed
You view gets reused/recycled from system - so you have to (re)set profile_thumb_image every time in getView.
If not, there is a chance that you get a recycled view where the image was set in a previous call of getView.
First don't make this variable global
HashMap song;
Take this into ur getView() method if possible make it final.
As #coyer told
You view gets reused/recycled from system - so you have to (re)set profile_thumb_image every time in getView
Hope this help u...if any questions u can ask

Load Bitmaps/images in ListView Adapter

I'm trying to add images in a ListView which has an ArrayAdapter. Fyi, the toList() is a conversion from iterator to a list of the given DBObject.
I override the View getView() and set a textview and an image.
private static class EventAdapter extends ArrayAdapter<DBObject> {
public EventAdapter(Context context, int resource, Iterable<DBObject> events) {
super(context, resource, toList(events));
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
LayoutInflater vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.adapter_event_list, null);
DBObject event = getItem(position);
if (event != null) {
//Get the logo if any
if( ((DBObject)event.get("events")).containsField("logo") ){
String logoURL = ((DBObject)((DBObject)event.get("events")).get("logo")).get("0").toString();
ImageView eventLogo = (ImageView) v.findViewById(R.id.eventLogoList);
new setLogo().execute(logoURL, eventLogo);
}
TextView title= (TextView) v.findViewById(R.id.eventTitleList);
title.setText( ((DBObject)event.get("events")).get("title").toString() );
}
return v;
}
protected static <T> List<T> toList( Iterable<T> objects ) {
final ArrayList<T> list = new ArrayList<T>();
for( T t : objects ) list.add(t);
return list;
}
//setLogo() method here. See below
}
The text in the textview is fine. However the images are getting messed up. They seem to load in wrong places in the list. The route of the code is: 1)Get from the DB (async) 2)populate the ListView 3) while populating load each image(second async).
Here is the setLogo() AsyncTask which is inside the EventAdapter above:
private class setLogo extends AsyncTask<Object,Void,Bitmap>{
ImageView eventLogo = null;
#Override
protected Bitmap doInBackground(Object...params) {
try{
Bitmap eventImage = downloadBitmap((String) params[0]);
eventLogo = (ImageView) params[1];
return eventImage;
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap eventImage) {
if(eventImage!=null && eventLogo!=null){
eventLogo.setImageBitmap(eventImage);
}
}
}
I did so (using an Async) which I believe is the correct way to load images from urls. I saw this post on multithreading and from which I borrowed the downloadBitmap() method.
As explained above the images are loaded in wrong places of the ListView. What can be a robust way to load them?
Also the idea to pass the v.findViewById(R.id.eventLogoList) inside the AsyncTask is that the program will distinguish each adapter's ImageView but it seems it doesn't.
Update
After following the problem that is causing this mix I found this SO question.
I altered my code in order to check if the if is causing the problem.
//Get the logo if any
if( ((DBObject)event.get("events")).containsField("logo") ){
String logoURL = ((DBObject)((DBObject)event.get("events")).get("logo")).get("0").toString();
ImageView eventLogo = (ImageView) row.findViewById(R.id.eventLogoList);
//new setLogo().execute(logoURL, eventLogo);
TextView title= (TextView) row.findViewById(R.id.eventTitleList);
title.setText( "Shit happens" );
}
Let's say I have 40 items. The Shit happens is set on the fields that a logo field exists. If I scroll down/up the order changes and the text gets messed up. It is because the stack created inside the loop is small than the maximum of the list..I guess... I am still struggling.
PS: I found this easy library to load images asynchronously instead of DYI stuff.
Update 2
I added an else with a static url. Because of the time it take to the image to load they are still misplaced.
I would really go for a good library like Picasso.
It will handle all the hard part for you and it's very well written.
http://square.github.io/picasso/

ArrayAdapter messed up the contents of the ListView when notifyDataSetChanged is called

I am developing an android app with a ListView/ArrayAdapter combo with the items being dynamically added when it receives a broadcast from another service.
Here is the initial setup:
postAdapter = new PostAdapter(this.getActivity(), R.layout.item, posts);
ListView list = (ListView) V.findViewById(R.id.listView1);
list.setAdapter(postAdapter);
There are some elements inside the list initially (stored inside posts).
The initial render of the listView from the adapter works perfectly.
However, when a broadcast is received from another service problem occurs.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String title= intent.getStringExtra("title");
String content= intent.getStringExtra("content");
String senderDesc= intent.getStringExtra("senderDesc");
String receiverDesc= intent.getStringExtra("receiverDesc");
Post newPost = new Post(title, content, senderDesc, receiverDesc);
posts.add(newPost);
postAdapter.notifyDataSetChanged();
}
};
At first, when the first 2 element is added, the listView still looks fine.
Until the listView is added to about 7 elements, then the next element is no longer rendered as the content of the element in question but the content of a previous element.
For example(pseudo for simplicity):
Below is the initial list:
1
2
3
And when the 4th, and 5th post is added, then the listView looks like:
1
2
3
4
5
as expected,
However, when the 6th and sometimes 7th item is added, then it will look like this
1
2
3
4
5
1
2 ...
Below is my custom PostAdapter function:
public class PostAdapter extends ArrayAdapter {
int resource;
public PostAdapter(Context context, int resource, List<Post> posts) {
super(context, resource, posts);
this.resource = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Setting up postView
RelativeLayout postView;
Post post = getItem(position);
String titleString = post.getTitle();
String contentString = post.getContent();
String senderDescString = post.getSenderDesc();
String receiverDescString = post.getReceiverDesc();
if(convertView == null) {
postView = new RelativeLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li;
li = (LayoutInflater)getContext().getSystemService(inflater);
li.inflate(resource, postView, true);
TextView contentView = (TextView) postView.findViewById(R.id.postContent);
contentView.setText(contentString);
} else {
postView = (RelativeLayout) convertView;
}
// Check if the post has been previously populated;
return postView;
}
}
I have spend over 10 hours on this and I don't know what is causing the problem.
If expert can point it out to me I really appreciate.
Thank you,
Dennis
I think View-reused make this happen, put the following method below getView() method comment, it will works. BTW, you should use ViewHolder pattern in AdapterView if you have a lot of items to display
TextView contentView = (TextView) postView.findViewById(R.id.postContent);
contentView.setText(contentString);
The problem is the else part when convertView is not null, do
else {
postView = (RelativeLayout) convertView;
setText(contentString);
}

Android ListFragment individually change row background color

I have a ListFragment where I want certain rows to be a certain color. I basically followed this: Creating a ListView and setting the background color of a view in each row
However, getView is never called. Does anyone know why?
public class TrackerFragment extends ListFragment
{
private String[] list;
#Override
public void onActivityCreated(Bundle myBundle)
{
super.onActivityCreated(myBundle);
list = null;
ListView lv = getListView();
setListAdapter(null);
setEmptyText("Touch a connection to view tracker information.");
lv.setTextFilterEnabled(true);
}
public void updateList(String[] list)
{
this.list = list;
setListAdapter(new ColoredArrayAdapter(getActivity(),R.layout.list_item,list));
}
}
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="7dp"
android:textSize="14sp"
android:id="#+id/line">
</TextView>
I am updating the list like this from my activity:
TrackerFragment tf = (TrackerFragment) fragmentManager.findFragmentById(R.id.tracker1);
tf.updateList(result);
My ColoredArrayAdapter
public class ColoredArrayAdapter extends ArrayAdapter{
private String[] list;
public ColoredArrayAdapter(Context context, int textViewResourceId,
Object[] objects) {
super(context, textViewResourceId, objects);
list = new String[objects.length];
for (int i = 0; i < list.length; i++)
list[i] = (String) objects[i];
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View vi = convertView;
ViewHolder holder;
if (convertView == null)
{
vi = LayoutInflater.from(getContext()).inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.line = (TextView) vi.findViewById(R.id.line);
vi.setTag(holder);
}
else
holder = (ViewHolder) vi.getTag();
for (int i = 0; i < list.length; i++)
{
if (list[i].contains("OUT OF LOCK"))
{
System.out.println("OUT OF LOCK");
holder.line.setText(list[i]);
//holder.line.setTextColor(R.color.white);
holder.line.setBackgroundResource(R.color.red);
}
else if(list[i].contains("IN LOCK"))
{
System.out.println("In LOCK");
holder.line.setText(list[i]);
//holder.line.setTextColor(R.color.white);
holder.line.setBackgroundResource(R.color.green);
}
else
holder.line.setText(list[i]);
}
return vi;
}
}
What am I doing wrong?
Edit: added list_item.xml, where line is found.
Edit2: added extended array adapter
Now my problem is that, every row is either all green or red, when I just want certain individual rows to be either red or green. Also, none of the text is showing up.
Your current getView implementation should be moved into a ListAdapter implementation instead of your TrackerFragment class. Since you're using ArrayAdapter, you can subclass that and put the code in there. ArrayAdapter already implements getView, but you'll override it to provide your specialized behavior.
The reason you're getting a NullPointerException is because you're calling getView and passing in the list view, which does not have a tag associated with it -- so holder = (ViewHolder) vi.getTag(); assigns null to holder. That said, you shouldn't be calling getView directly. The system will call that for you whenever it needs to display a list item. When the system calls the getView method, it initially passes in null to have the views created, and every call where convertView is not null is a view created by that method.
Looks like the same problem as the post you linked: the getView() method isn't nested inside the class.
Or your code doesn't show anything that would call it either.
The more I look over this, the more I wonder about the basic premise you are using. I think you're making it overly complicated. I would do it like this:
public View getView(View convertView)
{
View vi = convertView;
TextView viText = null;
if (vi == null)
vi = LayoutInflater.from(getActivity()).inflate(R.layout.list_item, null);
viText = (TextView)vi.findViewById(R.id.line);
if (viText == null) return vi;
String viString = viText.getText().toString();
if (viString.contains("OUT OF LOCK"))
{
viText.setBackgroundResource(R.color.red);
}
else if (viString.contains("IN LOCK"))
{
viText.setBackgroundResource(R.color.green);
}
return vi;
}
I don't think you are using the holder in the way you think... the loop you have in there will just loop through setting the background resource to whatever the last trigger to set the backgroundResource is, no matter what.
If I have missed the point in this, let me know. But, my basic thought would be to remove as much complexity as you can until it works, and if you've had to remove something important, slowly add it back in.

ListView ArrayAdapter, hiding children inside Row?

I feel a bit stupid as i can't find the answer to this question, which makes me think i'm actually asking the wrong question. However, here goes...
I have a list view, and a listviewitem defined in xml, with a couple of fields, nothing special. All set to visible.
Then I bind to my ListView using a custom ArrayAdapter, and want to hide one of my text views, on row 5. However, it seems to be hiding my TextView on item 0 and item 5. Which is a bit odd? I've simplified the code, to reproduce the problem and hopefully someone will be able to help me...
My Adapter
public class MenuScreenAdapter extends ArrayAdapter<String>
{
private List<String> _items;
private Context _context;
public MenuScreenAdapter(Context context, List<String> items)
{
super(context, R.layout.list_menu_item, items);
_context = context;
_items = items;
}
private MenuScreenAdapter(Context context, int textViewResourceId)
{
super(context, textViewResourceId);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_menu_item, null);
}
String o = _items.get(position);
if (o != null)
{
TextView tt = (TextView) v.findViewById(R.id.list_menu_item_name);
if (tt != null)
tt.setText(o);
if (position == 5)
tt.setVisibility(View.GONE);
}
return v;
}
}
My Binding Code
// Load everything up that we need
List<String> items = new ArrayList<String>();
items.add("One");
items.add("Two");
items.add("Three");
items.add("Four");
items.add("Five");
items.add("Six");
items.add("Seven");
items.add("Eight");
items.add("Nine");
items.add("Ten");
// Get the ListView, and set it's adapter. The HomeScreenAdapter
// takes care of the rest
ListView homeScreenListView = (ListView) _mainActivity.findViewById(R.id.view_home_list);
homeScreenListView.setOnItemClickListener(ItemSelected);
homeScreenListView.setAdapter(new MenuScreenAdapter(_mainActivity.getBaseContext(), items));
Thanks in advance!
Since row views are reused by ArrayAdapter, once the View.GONE is set, it will cary on to the next row, where this view will be reused. In your case, you set View.GONE to textview in the fifth row, moved list a little and arrayadapter decided to reuse your fifth row layout to display the first row, since no changes were done to it, the textView still remains hidden.
Just do the:
if (position == 5) {
tt.setVisibility(View.GONE);
} else {
tt.setVisibility(View.VISIBLE);
}
P.S. If you still haven't, watch a presentation about ListViews from google. Tons of usefult info there. ListViews

Categories

Resources