boolean variable unavailable in getView() - android

I never understand the getView() method fully. Here is a case:
Here I have isNoticeRead which is false you can see. But the line gets executed! And when the line in the if statement is executing, isNoticeRead is not found anywhere! If I even place my cursor over it, nothing happens (no tooltip). And it happens for the first item of the ListView. Can you please tell me what am I missing?
My full Adapter
public class NoticesListViewAdapter extends BaseAdapter{
Context context;
ArrayList<NoticeModel> items;
String[] readNotices;
public NoticesListViewAdapter(Context context, ArrayList<NoticeModel> items) {
this.context = context;
this.items = items;
readNotices = SharedPrefUtils.getMarkedNotices(context).split(SharedPrefUtils.SEPARATOR_READ_NOTICE);
}
#Override
public int getCount() {
return items.size();
}
#Override
public Object getItem(int position) {
return items.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_notices, null);
holder = new Holder();
holder.noticeID = (TextView) convertView.findViewById(R.id.noticeID);
holder.tvNotice = (TextView) convertView.findViewById(R.id.tvNotice);
holder.tvDateTime = (TextView) convertView.findViewById(R.id.tvDateTime);
holder.tvNoticeRead = (TextView) convertView.findViewById(R.id.tvNoticeRead);
convertView.setTag(holder);
}else{
holder = (Holder) convertView.getTag();
}
try {
String str = items.get(position).getId() + "";
holder.noticeID.setText(str);
holder.tvNotice.setText(items.get(position).getText());
holder.tvDateTime.setText(DateTimeUtils.changeDateTimeFormat(items.get(position).getDateTime(), DateTimeUtils.FORMAT8, DateTimeUtils.FORMAT3));
final boolean isNoticeRead = items.get(position).isRead();
if (isNoticeRead) {
holder.tvNoticeRead.setVisibility(View.VISIBLE);
}
// for(String s : readNotices) {
// if (s.equals(str)) {
// holder.tvNoticeRead.setVisibility(View.VISIBLE);
//// break;
// }
// }
}catch (Exception e){e.printStackTrace();}
return convertView;
}
class Holder{
TextView tvNotice, tvDateTime, noticeID, tvNoticeRead;
}
}

The views of your holder are being re-used by the List. Thus you may have an instance which is initialized with VISIBLE, but when the view is reused and filled, you don't reset its state - so it is still visible.
if (isNoticeRead) {
holder.tvNoticeRead.setVisibility(View.VISIBLE);
} else {
holder.tvNoticeRead.setVisibility(View.INVISIBLE);
}

when you make variable final then it's means unable to assigned value during execute because you make it final remove final or define isNoticeRead as field.
then it may be work fine for you..

Related

Android Listview is repeating items when scrolled

I have looked at other threads and I cannot see what is wrong with my listadapter. I have the view holder pattern and I am setting all the values for the list item outside of the convertview null check statement. Im not sure what other things would cause it to repeat the items.
public class ScheduledJobListAdapter extends BaseAdapter {
private static LayoutInflater inflater = null;
private ArrayList<Job> jobList;
private Context context;
public ScheduledJobListAdapter(Context context, ArrayList<Job> jobList) {
this.context = context;
this.jobList = jobList;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() { return jobList.size(); }
#Override
public Job getItem(int position) { return jobList.get(position); }
#Override
public long getItemId(int position) { return 0; }
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ScheduledViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item_scheduled_job,null);
holder = new ScheduledViewHolder();
holder.job = getItem(position);
holder.container = convertView.findViewById(R.id.scheduled_job_layout);
holder.routeOrder = convertView.findViewById(R.id.route_order_textview);
holder.location = convertView.findViewById(R.id.location_textview);
holder.jobRef = convertView.findViewById(R.id.job_ref_textview);
holder.statusIndicator = convertView.findViewById(R.id.status_indicator);
convertView.setTag(holder);
} else {
holder = (ScheduledViewHolder) convertView.getTag();
}
holder.routeOrder.setText(holder.job.getRouteOrder() + "");
holder.location.setText(holder.job.getLocation());
holder.jobRef.setText(holder.job.getJobReference());
return convertView;
}
}
class ScheduledViewHolder {
Job job;
LinearLayout container;
TextView routeOrder;
TextView location;
TextView jobRef;
ImageView statusIndicator;
}
Here's the problem:
holder.job = getItem(position);
Remember the views may be recycled as you scroll, and the job assigned maybe used unintentionally for other positions if you assigned it that way. To fix it, simply assign the job after the if-else condition:
if (convertView == null) {
// ...
} else {
// ...
}
holder.job = getItem(position); // Update the job by position
holder.routeOrder.setText(holder.job.getRouteOrder() + "");
holder.location.setText(holder.job.getLocation());
holder.jobRef.setText(holder.job.getJobReference());

Favorite fragment using SharedPreference

I'm adding a favorite button to my android application that saves pharmacies
in a fragment using SharedPreference and i get this error "Unreachable statement" in the line where i change the color of the button favorite whene it's clicked
if (checkFavoriteItem(pharmacie)) {
holder.img_favorite.setImageResource(R.drawable.heart_red); /********error*********/
holder.img_favorite.setTag("red");
} else {
holder.img_favorite.setImageResource(R.drawable.heart_grey);
holder.img_favorite.setTag("grey");
}
return convertView;}
this is the full PharmacyArrayAdapter activity:
public class PharmacyArrayAdapterfav extends ArrayAdapter<Pharmacie> {
Context myContext;
int layoutResourceId;
List<Pharmacie> pharmacie;
SharedPreference sharedPreference;
private Context context;
public PharmacyArrayAdapterfav(Context context, List<Pharmacie> pharmacie) {
super(context, R.layout.liste_layout, pharmacie);
this.context = context;
this.pharmacie = pharmacie;
myContext=context;
sharedPreference = new SharedPreference();
}
private class ViewHolder {
TextView nomTextView;
TextView villeTextView;
ImageView img_favorite;
TextView lonTextView;
}
#Override
public int getCount() {
return pharmacie.size();
}
#Override
public Pharmacie getItem(int position) {
return pharmacie.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//return super.getView(position, convertView, parent);
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.fragment_product_list, null);
holder = new ViewHolder();
holder.nomTextView = (TextView) convertView
.findViewById(R.id.textViewNom);
holder.villeTextView = (TextView) convertView
.findViewById(R.id.txtViewVille);
holder.img_favorite = (ImageView) convertView
.findViewById(R.id.img_favorite);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Pharmacie pharmacie = (Pharmacie) getItem(position);
holder.nomTextView.setText(pharmacie.getNom());
holder.villeTextView.setText(pharmacie.getVille());
return convertView;
if (checkFavoriteItem(pharmacie)) {
holder.img_favorite.setImageResource(R.drawable.heart_red);
holder.img_favorite.setTag("red");
} else {
holder.img_favorite.setImageResource(R.drawable.heart_grey);
holder.img_favorite.setTag("grey");
}
return convertView;}
/*Checks whether a particular product exists in SharedPreferences*/
public boolean checkFavoriteItem(Pharmacie checkProduct) {
boolean check = false;
List<Pharmacie> favorites = sharedPreference.getFavorites(context);
if (favorites != null) {
for (Pharmacie product : favorites) {
if (product.equals(checkProduct)) {
check = true;
break;
}
}
}
return check;
}
#Override
public void add(Pharmacie phar) {
super.add(phar);
pharmacie.add(phar);
notifyDataSetChanged();
}
#Override
public void remove(Pharmacie phar) {
super.remove(phar);
pharmacie.remove(phar);
notifyDataSetChanged();
}
}
And also i want to know how to save the list to a specific user that finds his list of favorites after he logs in and clicks favorites button ,please i need help, thank you.
Oh my god, I totally didn't see a very obvious reason why you have unreachable code - you have an extra return that shouldn't be there:
Pharmacie pharmacie = (Pharmacie) getItem(position);
holder.nomTextView.setText(pharmacie.getNom());
holder.villeTextView.setText(pharmacie.getVille());
return convertView; //THIS ONE -> just remove it and it'll work
if (checkFavoriteItem(pharmacie)) {
holder.img_favorite.setImageResource(R.drawable.heart_red);
holder.img_favorite.setTag("red");
} else {
holder.img_favorite.setImageResource(R.drawable.heart_grey);
holder.img_favorite.setTag("grey");
}
return convertView;
}
Unreachable code warning is usually this^, having a return that is not in an if branch and some code after it, it means that the method will always return at that point and will never run the code below it. It's not an error per se, it's just IDE warning you that you might have mistakenly put return where you didn't mean to.

notifyDatasetChanged is not working inside the getView() method for Custom Adapter In Android

I am basically trying hide and show a text in the list row when I am clicking a button in the list row. I have added the onClick() for the button inside getView() method and then calling the notifyDataSetChanged(). But it is not working. No change in the text visibility. Here is my custom Adapter code:
public class ListAdapter extends BaseAdapter {
private Context context;
private List<String> mListQuestion = null;
private List<String> mListAnswer = null;
ViewHolder holder = null;
boolean flag = false;
public ListAdapter(Context context, List<String> question, List<String> answer ) {
this.mListQuestion = question;
this.mListAnswer = answer;
this.context = context;
}
#Override
public Object getItem(int position)
{
return mListQuestion.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getCount() {
return mListQuestion.size();
}
#Override
#SuppressWarnings("deprecation")
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.list_faq_item, null);
holder = new ViewHolder();
holder.tvQuestion = (TextView) convertView.findViewById(R.id.text);
holder.tvAns = (TextView) convertView.findViewById(R.id.anstext);
holder.ivArrow = (Button)convertView.findViewById(R.id.arrow_expand);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.tvQuestion.setText(mListQuestion.get(position));
holder.tvAns.setText(mListAnswer.get(position));
holder.ivArrow.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if (flag == false)
{
Logger.d("arrow clicked when flag is false");
holder.tvAns.setVisibility(View.VISIBLE);
holder.ivArrow.setBackgroundResource(R.drawable.up_arrow);
flag = true;
}
else if (flag == true)
{
Logger.d("arrow clicked when flag is true");
holder.tvAns.setVisibility(View.GONE);
holder.ivArrow.setBackgroundResource(R.drawable.down_arrow);
flag = false;
}
notifyDataSetChanged();
}
});
return convertView;
}
static class ViewHolder {
TextView tvQuestion;
TextView tvAns;
Button ivArrow;
}
}
Can someone please tell what I am doing wrong here.
Thanks in Advance.
-Arindam.
public class ListAdapter extends BaseAdapter {
private Context context;
private List<String> mListQuestion = null;
private List<String> mListAnswer = null;
ViewHolder holder = null;
private List<Boolean> textViewVisibileState;
public ListAdapter(Context context, List<String> question, List<String> answer ) {
this.mListQuestion = question;
this.mListAnswer = answer;
this.context = context;
this.textViewVisibileState=new ArrayList<>(Arrays.asList(new Boolean[getCount()]));
Collections.fill(this.textViewVisibileState,false);
}
#Override
public Object getItem(int position)
{
return mListQuestion.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getCount() {
return mListQuestion.size();
}
#Override
#SuppressWarnings("deprecation")
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.list_faq_item, null);
holder = new ViewHolder();
holder.tvQuestion = (TextView) convertView.findViewById(R.id.text);
holder.tvAns = (TextView) convertView.findViewById(R.id.anstext);
holder.ivArrow = (Button)convertView.findViewById(R.id.arrow_expand);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.tvQuestion.setText(mListQuestion.get(position));
holder.tvAns.setText(mListAnswer.get(position));
if(textViewVisibileState.get(position))
{
holder.tvAns.setVisibility(View.GONE);
holder.ivArrow.setBackgroundResource(R.drawable.down_arrow);
}
else
{
Logger.d("arrow clicked when flag is false");
holder.tvAns.setVisibility(View.VISIBLE);
holder.ivArrow.setBackgroundResource(R.drawable.up_arrow);
}
holder.ivArrow.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if (textViewVisibileState.get(position))
{
textViewVisibileState.set(position,false);
}
else
{
textViewVisibileState.set(position,true);
}
notifyDataSetChanged();
}
});
return convertView;
}
static class ViewHolder {
TextView tvQuestion;
TextView tvAns;
Button ivArrow;
}
}
This will work.
The variable flag is not context sensitive to object holder. So flag is always = false in your case. How about setVisibility(View.GONE) initially? And then setVisibility(View.VISIBLE) ONLY when ivArrow is clicked upon.
Calling notifyDataSetChanged() causes ListView to rebuild everything. It will remove its child views, call getView() for all the items that are visible, and thus you will rebind all the data for those items.
But your data hasn't actually changed. You haven't modified anything in the questions list, so binding the data again is meaningless. Instead you have tried to change something in your ViewHolder object, but there's no guarantee that the convertView you get after a notifyDataSetChanged() is for the same position as before, so it's possible that some other item has been affected (or perhaps none at all?).
Try removing the call to notifyDataSetChanged() from the OnClickListener. A visibility change should cause a re-layout of the view hierarchy, but as long as you haven't told ListView that the data has changed, it should keep all its current children.
Create an instance of the adapter, e.g Adapter myAdapter = new Adapter, set it to a listview or recyclerview e.g listview.setAdapter(mydapter) and everytime you add new data to it call adapter.notifyDataSetChanged()

Android Base Adapter

I am adding multiple UI elements like SeekBar,ImageView,TextView dynamically to the ListView.But Whenever I try to get the reference to these elements,I am always getting reference to the last element only.
e.g I have multiple SeekBar.When i press play button that SeekBar should update.But the problem is when i press any number of play button only SeekBar at last position is getting updated.
I tried
seekbar.setTag(position);
But of no use.
Finally the solution is, I made my ViewHolder class's object local inside getView() method and assigned it to a global ViewHolder class's object on play button's OnClickListener.This change solved my problem like a miracle.
The tag you are setting should be instance of your ViewHolder class.
Your code can be like this -
public class YourTeamAdapter extends BaseAdapter {
private static Context context;
private ArrayList<TopDataModel> mList;
public YourTeamAdapter(Context c, ArrayList<TopDataModel> list) {
mList = list;
context = c;
}
#Override
public int getCount() {
return mList.size();
}
// get item at givin position
#Override
public TopDataModel getItem(int position) {
return mList.get(position);
}
// get itemID at givin position
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.activity_team_status_list_item, null, true);
holder = new Holder(convertView);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
holder.tvName.setText(getItem(position).getName());
holder.tvRank.setText(getItem(position).getRank());
try {
if (getItem(position).getImage() != null &&
!getItem(position).getImage().equalsIgnoreCase("")) {
holder.imageView.setImageBitmap(SharedHelper.decodeBase64(getItem(position).getImage()));
}
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
private static class Holder {
TextView tvName;
TextView tvRank;
CircularImageView imageView;
public Holder(View convertView) {
this.tvName = (TextView) convertView.findViewById(R.id.name);
this.tvRank = (TextView) convertView.findViewById(R.id.rank);
this.imageView = (CircularImageView) convertView.findViewById(R.id.image);
}
}
}

How to add a dynamic view to a ListView item at runtime?

My problem is that I don't know whether I should use multiple list view or a custom listview item adapter which can grows dynamically. For example, for a particular user, they can have multiple activities:
- Take a picture
- Say something
- Checking in
- ...
Apparently, this list can grows as the user has done more activities. Most of the time, I often create a custom item adapter which extends from BaseAdapter and use the ItemHolder pattern as follows:
public class PlaceItemAdapter extends BaseAdapter {
private Activity context;
private List<Place> places;
private boolean notifyChanged = false;
public PlaceItemAdapter(Activity context, List<Place> places) {
super();
this.context = context;
this.places = places;
}
public int getCount() {
return places.size();
}
public Object getItem(int position) {
return places.get(position);
}
public long getItemId(int position) {
return position;
}
public static class ItemViewHolder {
TextView nameTextView;
TextView typesTextView;
TextView ratingTextView;
ImageView mapIconImageView;
}
public View getView(int position, View convertView, ViewGroup parent) {
ItemViewHolder holder;
LayoutInflater inflater = context.getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.place_item, null);
holder = new ItemViewHolder();
holder.nameTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_name);
holder.typesTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_address);
holder.ratingTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_rating);
holder.mapIconImageView = (ImageView) convertView.findViewById(R.id.place_item_xml_imageview_location_icon);
convertView.setTag(holder);
}
else {
holder = (ItemViewHolder) convertView.getTag();
}
holder.nameTextView.setText(places.get(position).getName());
holder.typesTextView.setText(places.get(position).getAddress());
holder.ratingTextView.setText(Integer.toString(places.get(position).getRating()));
/*
* This task is time consuming!
* TODO: find a workaround to handle the image
*/
// holder.mapIconImageView.setImageBitmap(DownloadImageHelper.downloadImage(places.get(position).getIconUrl()));
holder.mapIconImageView.setImageResource(R.drawable.adium);
return convertView;
}
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
notifyChanged = true;
}
}
Using this method, the number GUI widgets is fixed which means I can't make my listview item look like the picture below.
public static class ItemViewHolder {
TextView nameTextView;
TextView typesTextView;
TextView ratingTextView;
ImageView mapIconImageView;
}
My initial approach was to create a dynamic view nested inside an adapter item, however it will produce duplicate views. To avoid duplicate view, I have set convertView to null which means each time it loads, it will create a new ItemViewHolder which eventually eats up all my memory. :( So how could I handle this situation? A minimal working example would be greatly appreciated.
Duplicate View
public class FriendFeedItemAdapter extends BaseAdapter {
private List<FriendFeedItem> items;
private Activity context;
private static LayoutInflater inflater;
public ImageLoader imageLoader;
private ItemViewHolder viewHolder;
public FriendFeedItemAdapter(Activity context, List<FriendFeedItem> items) {
this.context = context;
this.items = items;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(context.getApplicationContext());
}
public int getCount() {
return items.size();
}
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
public static class ItemViewHolder {
TableLayout table;
ImageView imageViewUserPicture;
TextView textViewUsername;
TextView textViewWhatUserDo;
TextView textViewWhere;
TextView textViewTime;
ImageView imageViewSnapPictureBox;
TextView textViewWriteOnWallMessageBox;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.friend_list_feed_item, null);
viewHolder = new ItemViewHolder();
viewHolder.table = (TableLayout) convertView.findViewById(R.id.friend_list_feed_item_xml_tablelayout_table);
viewHolder.imageViewUserPicture = (ImageView) convertView.findViewById(R.id.friend_list_feed_item_xml_imageview_user_picture);
viewHolder.textViewUsername = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_username);
viewHolder.textViewWhatUserDo = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_what_user_do);
viewHolder.textViewWhere = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_where);
viewHolder.textViewTime = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_at_what_time);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ItemViewHolder) convertView.getTag();
}
imageLoader.displayImage(items.get(position).getFriendPictureUrl(), viewHolder.imageViewUserPicture);
viewHolder.textViewUsername.setText(items.get(position).getFriendName());
viewHolder.textViewWhere.setText("at " + items.get(position).getPlaceName());
viewHolder.textViewTime.setText("#" + items.get(position).getActivityTime());
if (items.get(position).getChallengeType() == Challenge.Type.CHECK_IN) {
viewHolder.textViewWhatUserDo.setText("has checked in.");
}
else if (items.get(position).getChallengeType() == Challenge.Type.SNAP_PICTURE) {
viewHolder.textViewWhatUserDo.setText("has snap a picture.");
// add picture box
View rowView = inflater.inflate(R.layout.snap_picture_row_item, null);
viewHolder.imageViewSnapPictureBox = (ImageView) rowView.findViewById(R.id.snap_picture_row_item_xml_imageview_picture);
imageLoader.displayImage(items.get(position).getActivitySnapPictureUrl(), viewHolder.imageViewSnapPictureBox);
viewHolder.table.addView(rowView);
}
else if (items.get(position).getChallengeType() == Challenge.Type.WRITE_ON_WALL) {
viewHolder.textViewWhatUserDo.setText("has written a message on wall.");
// add message box
View rowView = inflater.inflate(R.layout.write_on_wall_row_item, null);
viewHolder.textViewWriteOnWallMessageBox = (TextView) rowView.findViewById(R.id.write_on_wall_row_item_xml_textview_wall_message);
viewHolder.textViewWriteOnWallMessageBox.setText(items.get(position).getActivityComment());
viewHolder.table.addView(rowView);
}
else if (items.get(position).getChallengeType() == Challenge.Type.QUESTION_ANSWER) {
viewHolder.textViewWhatUserDo.setText("has answered a question.");
}
else { // Challenge.Type.OTHER
viewHolder.textViewWhatUserDo.setText("has done some other challenges.");
}
return convertView;
}
}
Extensive Memory Usage
public View getView(int position, View convertView, ViewGroup parent) {
ItemViewHolder holder = null;
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.friend_list_feed_item, null);
// create holder
holder = new ItemViewHolder();
// default field
holder.table = (TableLayout) convertView.findViewById(R.id.friend_list_feed_item_xml_tablelayout_table);
holder.imageViewUserPicture = (ImageView) convertView.findViewById(R.id.friend_list_feed_item_xml_imageview_user_picture);
holder.textViewUsername = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_username);
holder.textViewWhatUserDo = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_what_user_do);
holder.textViewWhere = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_where);
holder.textViewTime = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_at_what_time);
convertView.setTag(holder);
holder.imageViewUserPicture.setImageURI(items.get(position).getFriendPictureUri());
holder.textViewUsername.setText(items.get(position).getFriendName());
holder.textViewWhere.setText("at " + items.get(position).getPlaceName());
holder.textViewTime.setText("#" + items.get(position).getActivityTime());
if (items.get(position).getChallengeType() == Challenge.Type.CHECK_IN) {
holder.textViewWhatUserDo.setText("has checked in.");
}
else if (items.get(position).getChallengeType() == Challenge.Type.SNAP_PICTURE) {
holder.textViewWhatUserDo.setText("has snap a picture.");
// add picture box
View rowView = inflater.inflate(R.layout.snap_picture_row_item, null);
holder.imageViewSnapPictureBox = (ImageView) rowView.findViewById(R.id.snap_picture_row_item_xml_imageview_picture);
holder.imageViewSnapPictureBox.setImageURI(items.get(position).getActivitySnapPictureUri());
holder.table.addView(rowView);
}
else if (items.get(position).getChallengeType() == Challenge.Type.WRITE_ON_WALL) {
holder.textViewWhatUserDo.setText("has written a message on wall.");
// add message box
View rowView = inflater.inflate(R.layout.write_on_wall_row_item, null);
holder.textViewWriteOnWallMessageBox = (TextView) rowView.findViewById(R.id.write_on_wall_row_item_xml_textview_wall_message);
holder.textViewWriteOnWallMessageBox.setText(items.get(position).getActivityComment());
holder.table.addView(rowView);
}
else if (items.get(position).getChallengeType() == Challenge.Type.QUESTION_ANSWER) {
holder.textViewWhatUserDo.setText("has answered a question.");
}
else { // Challenge.Type.OTHER
holder.textViewWhatUserDo.setText("has done some other challenges.");
}
return convertView;
}
If you have small number of possible variants (on your screenshots I can see 2 different list items) You have two possible variants:
Setup count of different types by this method, and provide type for every item - and you can use convertView.
Create "full" list item view and set visibility for elements, that you don't want to see in particular item.
Some code for #2:
public class ListTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
List<Element> list = new ArrayList<Element>();
list.add(new Element(0));
list.add(new Element(0));
list.add(new Element(1));
list.add(new Element(0));
list.add(new Element(1));
list.add(new Element(1));
list.add(new Element(0));
list.add(new Element(0));
list.add(new Element(1));
list.add(new Element(1));
list.add(new Element(1));
list.add(new Element(0));
list.add(new Element(0));
list.add(new Element(1));
list.add(new Element(0));
list.add(new Element(0));
((ListView) findViewById(android.R.id.list)).setAdapter(new SampleAdapter(this, list));
}
private class SampleAdapter extends BaseAdapter {
private List<Element> list;
private Context context;
public SampleAdapter(Context context, List<Element> list) {
this.list = list;
this.context = context;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Element getItem(int position) {
return list.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
switch (getItemViewType(position)) {
case 0:
convertView = new CheckBox(context);
break;
default:
convertView = new Button(context);
break;
}
// Output here shows that you can lay on getItemViewType(position) as indicator of convertView type or structure
Log.e("test", getItemViewType(position) + ": " + convertView.getClass().getSimpleName());
return convertView;
}
#Override
public int getItemViewType(int position) {
return getItem(position).type;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public long getItemId(int position) {
return position;
}
}
private class Element {
public int type;
public Element(int type) {
this.type = type;
}
}
}
A custom adapter would solve your problem. This is because you can change the views that are being added to each row in the Listview, because you can change the content via logic that you implement in the custom adapter.
When the getView() method returns a view that is not null, this means for that particular row there is a view that was already there. As such if this is the case, you may or may not want to change content in that specific view. Or you could build a brand new view with dynamic content for that particular row.
One thing to note is that getView() will be called as many times as there are items found in your adapter.
Here's an idea that'll probably enable you to introduce as many item types as you like without having to modify adapter every time you do:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
AbstractItem abstractItem = ((AbstractItem)getItem(position));
// if null or new item type is different than the one already there
if (convertView == null || (convertView.getTag() != null
&& ((AbstractItem)convertView.getTag()).getType().equals(abstractItem.getType())) {
convertView = abstractItem.inflateSelf(getContext());
}
abstractItem.fillViewWithData(convertView);
convertView.setTag(abstractItem);
return convertView;
}
public class AbstractItem {
public abstract View inflateSelf(Context context);
public abstract String getType();
public abstract void fillViewWithData(View view);
}
public class PictureSnapItem extends AbstractItem {
// data fields
WeakReference<Bitmap> wBitmap;
String pictureComment;
...
public abstract View inflateSelf(Context context) {
// get layout inflater, inflate a layout resource, return
return ((Activity)context).getLayoutInflater.inflate(R.layout.picture_snap_item);
}
public abstract String getType() {
// return something class-specific, like this
return getClass().getCanonicalName();
}
public abstract void fillViewWithData(View view) {
// fill the view with data from fields, assuming view has been
// inflated by this very class's inflateSelf(), maybe throw exception if
// required views can't be found
ImageView img = (ImageView) view.findViewById(R.id.picture);
TextView comment = (TextView) view.findViewById(R.id.picture_comment)
}
}
... and then extend AbstractItem and add instances to adapter, no need to add any if clauses to getView() any more.

Categories

Resources