1

I have an list with an custom adapter, and upon refresh I want to add new data to be displayed(if any available).

But the list isn't being update. I tried all the methods with notifyDataSetChanged for the adapter but it's not updated.

Please help. I lost so much time with this and I feel like I'm loosing my mind with this one.

Here is the code: NewsFeedArrayAdapter

    public class NewsFeedArrayAdapter extends ArrayAdapter<FeedItem> {
    private final String TAG_DEBUG = this.getClass().getName();

    private LayoutInflater inflator;

    public final static String PREFS_NAME = "shared_pref_eid";

    ImageLoader imageLoader;

    Utils utils;

    public NewsFeedArrayAdapter(Activity context) {
        super(context, R.layout.feed_story_content);
        this.utils = new Utils(context);

        inflator = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        imageLoader = ImageLoader.getInstance(context);
    }

    /**
     * Static Inner class.
     * 
     * Makes the ListView more efficient since Android recycles views in a ListView.
     */
    public static class ViewHolder {
        public ImageView profilePicture, image;
        public TextView author, timePast, message, likes, comments;
        public LinearLayout like, comment, share, likesCommentsCounter;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = null;

        FeedItem feedItem = FeedItemParser.FEEDS.get(position);
        ViewHolder holder = null;
        if (convertView == null) {
            rowView = inflator.inflate(R.layout.feed_story_content, parent, false);
            holder = new ViewHolder();
            holder.profilePicture = (ImageView) rowView.findViewById(R.id.feed_story_profile_picture);
            holder.author = (TextView) rowView.findViewById(R.id.feed_story_author);
            holder.timePast = (TextView) rowView.findViewById(R.id.feed_story_time_past);
            holder.message = (TextView) rowView.findViewById(R.id.feed_story_message);
            holder.image = (ImageView) rowView.findViewById(R.id.feed_story_image);
            holder.like = (LinearLayout) rowView.findViewById(R.id.feed_feedback_like_container);
            holder.comment = (LinearLayout) rowView.findViewById(R.id.feed_feedback_comment_container);
            holder.share = (LinearLayout) rowView.findViewById(R.id.feed_feedback_share_container); 
            holder.likes = (TextView) rowView.findViewById(R.id.feed_story_likes);
            holder.comments = (TextView) rowView.findViewById(R.id.feed_story_comments);
            rowView.setTag(holder);            
        } else {
            rowView = convertView;
            holder = ((ViewHolder) rowView.getTag());
        }
        Log.i(TAG_DEBUG, "feedItem = " + feedItem);
        if (feedItem != null) {
            if (!TextUtils.isEmpty(feedItem.feed_story_from_name)) {
                holder.author.setText(feedItem.feed_story_from_name);
            } else {
                holder.author.setText("Unknown");
            }

            if (!TextUtils.isEmpty(feedItem.feed_story_created_time)) {

                // Convert the date to calendar date
                Calendar calendarDate = null;
                try {
                    calendarDate = ISO8601.toCalendar(feedItem.feed_story_created_time);
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                CharSequence relativeTimeSpan = DateUtils.getRelativeTimeSpanString(
                        calendarDate.getTimeInMillis(), 
                        System.currentTimeMillis(), 
                        DateUtils.SECOND_IN_MILLIS);
                holder.timePast.setText(relativeTimeSpan);

            } else {
                holder.timePast.setText("Unknown");
            }
            Log.i(TAG_DEBUG, "feedItem.feed_story_message = " + feedItem.feed_story_message);
            if (!TextUtils.isEmpty(feedItem.feed_story_message)) {
                holder.message.setText(feedItem.feed_story_message);    
            } else {
                holder.message.setText("Unkown");
//              holder.message.setVisibility(View.GONE);
            }

            // Display the icon of the feed
            int defaultResourceIcon = R.drawable.no_avatar;
            if (feedItem.feed_story_from_id != null) {
                String iconUrl = "https://graph.facebook.com/" + feedItem.feed_story_from_id + "/picture?type=normal";
                if (Session.getActiveSession() != null && 
                    Session.getActiveSession().getAccessToken() != null) {
                    iconUrl += "&access_token=" + Session.getActiveSession().getAccessToken();  
                }
                Log.i(TAG_DEBUG, "iconUrl = " + iconUrl);
                imageLoader.displayImage(iconUrl, holder.profilePicture, 70, defaultResourceIcon);
            } else {
                imageLoader.cancelDisplayTaskFor(holder.profilePicture);
                holder.profilePicture.setImageResource(defaultResourceIcon);
            }

            // Display the picture of the feed
            int defaultResourcePicture = R.drawable.empty;
            if (!TextUtils.isEmpty(feedItem.feed_story_picture)) {
                holder.image.setVisibility(View.VISIBLE);
                Log.i(TAG_DEBUG, "feed_picture = " + feedItem.feed_story_picture + "\nfeed_picture_height = " + feedItem.feed_story_picture_height);
                imageLoader.displayImage(feedItem.feed_story_picture, holder.image, -1, defaultResourcePicture);
            } else {
                imageLoader.cancelDisplayTaskFor(holder.image);
//              holder.image.setImageResource(defaultResourcePicture);
                holder.image.setVisibility(View.GONE);
            }



            if (!TextUtils.isEmpty(feedItem.feed_story_likes)) {
                holder.likes.setVisibility(View.VISIBLE);
                String likes = feedItem.feed_story_likes + " like";
                if (!feedItem.feed_story_likes.contentEquals("1")) {
                    likes += "s";
                }
                holder.likes.setText(likes);
            } else {
                holder.likes.setVisibility(View.GONE);
            }

            if (!TextUtils.isEmpty(feedItem.feed_story_comments)) {
                holder.comments.setVisibility(View.VISIBLE);
                String comments = feedItem.feed_story_comments + " comment";
                if (!feedItem.feed_story_comments.contentEquals("1")) {
                    comments += "s";
                }
                holder.comments.setText(comments);
            } else {
                holder.comments.setVisibility(View.GONE);
            }       

            holder.like.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    utils.customToast("Like content - TBA");
                }
            });

            holder.comment.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    utils.customToast("Comment section - TBA");
                }
            });

            holder.share.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    utils.customToast("Sharing content - TBA");
                }
            });
        }
    return rowView;
  }

    @Override
    public int getCount() {
        return FeedItemParser.FEEDS.size();
    }
}

The adapter on the list is set after the first request, when I get my first results, like this:

ListView actualListView = mPullRefreshListView.getRefreshableView();

// Need to use the Actual ListView when registering for Context Menu
registerForContextMenu(actualListView);

// Sort the list before displaying
Collections.sort(FeedItemParser.FEEDS, Comparators.CREATED_TIME);

// Set the custom adapter
customAddapter = new NewsFeedArrayAdapter(activity);

// Populate the fragment with the data from JSON
actualListView.setAdapter(customAddapter);

FeedItemParser is an custom class where I store my custom objects:

public class FeedItemParser {   
    // JSON Node names
    public static final String
        TAG_DATA = "data",                      // Array
            TAG_ID = "id",                      // String
            TAG_FROM = "from",                  // Object
                TAG_FROM_ID = "id",             // String
                TAG_FROM_CATEGORY = "category", // String
                TAG_FROM_NAME = "name",         // String
            TAG_TO = "to",                      // Object
                TAG_TO_DATA = "data",           // Array
                    TAG_TO_DATA_ID = "id",      // String
                    TAG_TO_DATA_NAME = "name",  // String
            TAG_MESSAGE = "message",            // String
            TAG_PICTURE = "picture",            // String
            TAG_ACTIONS = "actions",            // Array
                TAG_ACTIONS_NAME = "name",      // String
                TAG_ACTIONS_LINK = "link",      // String
            TAG_PRIVACY = "privacy",            // Object
                TAG_PRIVACY_VALUE = "value",    // String
            TAG_TYPE = "type",                  // String
            TAG_STATUS_TYPE = "status_type",    // String
            TAG_CREATED_TIME = "created_time",  // String
            TAG_UPDATED_TIME = "updated_time",  // String
            TAG_LIKES = "likes",                // Object 
                TAG_LIKES_COUNT = "count",      // String
            TAG_COMMENTS = "comments",          // Object
                TAG_COMMENTS_DATA = "data",     // Array
            TAG_PAGING = "paging",              // Object
                TAG_PAGING_PREVIOUS = "previous",// String
                TAG_PAGING_NEXT = "next";       // String

    /**
     * An array of Shelter items.
     */
    public static List<FeedItem> FEEDS = new ArrayList<FeedItem>();

    /**
     * A map of Array items, by ID.
     */
    public static Map<String, FeedItem> FEED_MAP = new HashMap<String, FeedItem>();

    public static void addItem(FeedItem item) {
        FEEDS.add(FEEDS.size(), item);
        FEED_MAP.put(item.feed_story_id, item);
    }

    public static void addPicture (String feed_story_id, String picture, String height) {
        FeedItem feedItem = FEED_MAP.get(feed_story_id);
        feedItem.feed_story_picture = picture;
        feedItem.feed_story_picture_height = height;
    }

    public static class FeedItem {
        public String feed_story_id, feed_story_from_id, feed_story_from_category,
            feed_story_from_name, feed_story_message, feed_story_picture, feed_story_picture_height,
            feed_story_privacy, feed_story_type, feed_story_status_type, feed_story_created_time,
            feed_story_updated_time, feed_story_likes, feed_story_comments;
        /**
         * @param feed_story_id
         * @param feed_story_from_id
         * @param feed_story_from_category
         * @param feed_story_from_name
         * @param feed_story_message
         * @param feed_story_picture
         * @param feed_story_privacy
         * @param feed_story_type
         * @param feed_story_status_type
         * @param feed_story_created_time
         * @param feed_story_updated_time
         */
        public FeedItem(String feed_story_id, String feed_story_from_id, String feed_story_from_category,
                String feed_story_from_name, String feed_story_message, String feed_story_picture,
                String feed_story_picture_height, String feed_story_privacy, String feed_story_type, 
                String feed_story_status_type, String feed_story_created_time, String feed_story_updated_time,
                String feed_story_likes, String feed_story_comments) {
            this.feed_story_id = feed_story_id;
            this.feed_story_from_id = feed_story_from_id;
            this.feed_story_from_category = feed_story_from_category;
            this.feed_story_from_name = feed_story_from_name;
            this.feed_story_message = feed_story_message;
            this.feed_story_picture = feed_story_picture;
            this.feed_story_picture_height = feed_story_picture_height;
            this.feed_story_privacy = feed_story_privacy;
            this.feed_story_type = feed_story_type;
            this.feed_story_status_type = feed_story_status_type;
            this.feed_story_created_time = feed_story_created_time;
            this.feed_story_updated_time = feed_story_updated_time;
            this.feed_story_likes = feed_story_likes;
            this.feed_story_comments = feed_story_comments;
        }

        @Override
        public String toString() {
            return feed_story_message;
        }
    }
}

When I request new data(refresh), I add the new data in my object (the same way I do the first time):

FeedItemParser.addItem(new FeedItem(
                                id,
                                from_id,
                                from_category,
                                from_name,
                                message,
                                null,   // Will be gotten through another request
                                null, 
                                privacy_value, 
                                type,
                                status_type, 
                                created_time, 
                                updated_time,
                                likes,
                                comments));

After that I call

ListView actualListView = mPullRefreshListView.getRefreshableView();

// Need to use the Actual ListView when registering for Context Menu
registerForContextMenu(actualListView);

// Sort the list before displaying
Collections.sort(FeedItemParser.FEEDS, Comparators.CREATED_TIME);

// Notify list adapter to update the list
customAddapter.notifyDataSetChanged(); 

SOLUTION

Based on the recommendations of @Selvin I have managed to update my list after adding more data. Basically I changed my adapter(I'm not using an filtered list anymore, but I'm directly using my custom objects). And after I add new Object, I update the list by calling notifyDataSetChanged() on the existing adapter. I have also update my code, maybe it will help someone else that is stuck is this situation.

Thanks again @Selvin.

Ionut Negru
  • 6,186
  • 4
  • 48
  • 78
  • 1
    could you show as where you are adding this new item to `customAddapter.filteredModelItemsArray` ? – Selvin Sep 20 '13 at 15:40
  • I set the adapter only the first time... when I call `customAddapter.notifyDataSetChanged();` shouldn't the list be updated ? – Ionut Negru Sep 23 '13 at 09:09
  • 1
    `customAddapter.filteredModelItemsArray` is used to "feed" getView ... it is a copy of your array ... `notifyDataSetChanged` just tells Adapter to: call `getCount()`, eventually call `getView(...)` again for visible items ... so if you do not change `filteredModelItemsArray` there will be no changes ... – Selvin Sep 23 '13 at 09:17
  • I see, so basically I need to call the constructor of my Custom Array Adapter again ... like `customAddapter = new NewsFeedArrayAdapter(activity, FeedItemParser.FEEDS);` and after that to call `actualListView.setAdapter(customAddapter);` and `customAddapter.notifyDataSetChanged();` ? – Ionut Negru Sep 23 '13 at 09:51
  • 1
    if you call setAdapter then there is no need for notifyDataSetChanged ... you can also add some methods to modify filteredModelItemsArray in your NewsFeedArrayAdapter ... you can also do not store your array in NewsFeedArrayAdapter since base class already has storage internally(you an get items calling ArrayAdapter.getItem(pos)(fx in getView instead using your own array/arraylist) and modify using ArrayAdapter.add/addAll/clear/remove ) – Selvin Sep 23 '13 at 09:59
  • Based on what you told me I managed to make it work, without setting the adapter again. In getView() on my adapter I call `FeedItem feedItem = FeedItemParser.FEEDS.get(position);` instead of `FeedItem feedItem = filteredModelItemsArray.get(position);` to get the item, and when I do the refresh I just sort the data again `Collections.sort(FeedItemParser.FEEDS, Comparators.CREATED_TIME)` and call `customAddapter.notifyDataSetChanged();` Is this ok in you opinion ? – Ionut Negru Sep 23 '13 at 10:09
  • 1
    does this work? yes! but storin data in some global variable and using it later in class instance doesn't looks like good practice for me ... anyway remeber to override getCount of your Adapter implementation to return count of items in FEEDS array ... next you could inherit your adapter from BaseAdapter since ArrayAdapter has no added value for you in such implementation ... or as i said you can use `feedItem = getItem(position);` and do not override getCount and do not store your own List inside NewsFeedArrayAdapter – Selvin Sep 23 '13 at 10:24
  • I see, I will try this method also and see if it improves the performance. Thank you again for all the help, also it made me understand lists and array adapters a little better. – Ionut Negru Sep 23 '13 at 10:28

0 Answers0