Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

First Sticky header remains sticky and following header do not replace it #314

Closed
royhenengel opened this issue Mar 8, 2017 · 14 comments
Closed
Labels

Comments

@royhenengel
Copy link

royhenengel commented Mar 8, 2017

Hi there,
First I would like to congratulate you on very impressive work!
One remark if I may.
I am relatively a new dev, and the current sample app is very difficult to understand.
It would be helpful if along with the current app that shows the full potential of the adapter, there would be a simple one that shows basic setup. I covered several times the wiki pages and couldn't find all of my answers and solutions there.
To our issue, I created a new project to test the adapter and figure out how the adapter works.
The three items models I created are these:

public class Article extends AbstractSectionableItem {
    private String itemType;
    private String title;
    private String subtitle;

    public Article(IHeader header, String itemType, String title, String subtitle) {
        super(header);
        this.itemType = itemType;
        this.title = title;
        this.subtitle = subtitle;
    }

    public String getItemType() {
        return itemType;
    }

    public void setItemType(String itemType) {
        this.itemType = itemType;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSubtitle() {
        return subtitle;
    }

    public void setSubtitle(String subtitle) {
        this.subtitle = subtitle;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Article) {
            Article inItem = (Article) o;
            return this.itemType.equals(inItem.getItemType());
        }
        return false;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.item_article;
    }

    @Override
    public ArticleViewHolder createViewHolder(FlexibleAdapter adapter, LayoutInflater inflater, ViewGroup parent) {
        return new ArticleViewHolder(inflater.inflate(getLayoutRes(),parent,false),adapter);
    }

    @Override
    public void bindViewHolder(FlexibleAdapter adapter, RecyclerView.ViewHolder holder, int position, List payloads) {

        ((ArticleViewHolder)holder).title.setText(title);
        ((ArticleViewHolder)holder).subtitle.setText(subtitle);
    }

    class ArticleViewHolder extends FlexibleViewHolder {
        private TextView title, subtitle;

        public ArticleViewHolder(View convertView, FlexibleAdapter adapter) {
            super(convertView, adapter);
            this.title = (TextView) convertView.findViewById(R.id.title);
            this.subtitle = (TextView) convertView.findViewById(R.id.subTitle);
        }
    }
}
public class Web extends AbstractFlexibleItem<Web.WebViewHolder> {
     private String itemType;
     private String title;
     private String subtitle;

    public Web(String itemType, String title, String subtitle) {
        this.itemType = itemType;
        this.title = title;
        this.subtitle = subtitle;
    }

    public String getItemType() {
        return itemType;
    }

    public void setItemType(String itemType) {
        this.itemType = itemType;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSubtitle() {
        return subtitle;
    }

    public void setSubtitle(String subtitle) {
        this.subtitle = subtitle;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Web) {
            Web inItem = (Web) o;
            return this.itemType.equals(inItem.getItemType());
        }
        return false;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.item_web;
    }

    @Override
    public WebViewHolder createViewHolder(FlexibleAdapter adapter, LayoutInflater inflater, ViewGroup parent) {
        return new WebViewHolder(inflater.inflate(getLayoutRes(),parent,false),adapter);
    }

    @Override
    public void bindViewHolder(FlexibleAdapter adapter, WebViewHolder holder, int position, List payloads) {
        holder.title.setText(title);
    }

    class WebViewHolder extends FlexibleViewHolder {
        private TextView title, subtitle;

        public WebViewHolder(View convertView, FlexibleAdapter adapter) {
            super(convertView, adapter,false);
            this.title = (TextView) convertView.findViewById(R.id.title);
            this.subtitle = (TextView) convertView.findViewById(R.id.subTitle);
        }
    }
}
public class Section extends AbstractHeaderItem<Section.SectionViewHolder>{

    private String itemType;
    private String title;

    public Section(String itemType, String title) {
        this.itemType = itemType;
        this.title = title;
    }

    public String getItemType() {
        return itemType;
    }

    public void setItemType(String itemType) {
        this.itemType = itemType;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Section) {
            Section inItem = (Section) o;
            return this.itemType.equals(inItem.getItemType());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return itemType.hashCode();
    }

    @Override
    public int getLayoutRes() {
        return R.layout.item_section;
    }

    @Override
    public SectionViewHolder createViewHolder(FlexibleAdapter adapter, LayoutInflater inflater, ViewGroup parent) {
        return new SectionViewHolder(inflater.inflate(getLayoutRes(),parent,false),adapter);
    }

    @Override
    public void bindViewHolder(FlexibleAdapter adapter, SectionViewHolder holder, int position, List payloads) {
        holder.title.setText(title);
    }

    class SectionViewHolder extends FlexibleViewHolder {
        private TextView title;

        public SectionViewHolder(View convertView, FlexibleAdapter adapter) {
            super(convertView, adapter, true);
            this.title = (TextView) convertView.findViewById(R.id.title);
        }
    }
}

And the MainActivity:

public class MainActivity extends AppCompatActivity {

    private Section section;

    /** General Obj */
    private RecyclerView mRecyclerView;
    private ArrayList<AbstractFlexibleItem> mResults;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mResults = new ArrayList<>();

        int headerCount = 0;
        int currentHeaderCount = 0;
        section = new Section("section", "section" + headerCount);
        for (int i=0; i<50; i++){

            headerCount++;
            if (headerCount == 6){
                currentHeaderCount++;
                section = new Section("section", "section " + currentHeaderCount);
                headerCount = 0;
            }


            Article item = new Article(section, "article", "title"+i, "subtitle"+i);
            mResults.add(item);

            Web web = new Web("web", "web" + i, "web"+ i);
            mResults.add(web);

        }

        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        mRecyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(this));
        mRecyclerView.setHasFixedSize(true);
        FlexibleAdapter<AbstractFlexibleItem> adapter = new FlexibleAdapter<>(mResults);
        mRecyclerView.setAdapter(adapter);
        adapter.setLongPressDragEnabled(true)
                .setHandleDragEnabled(true)
                .setSwipeEnabled(true)
                .setUnlinkAllItemsOnRemoveHeaders(true)
                // Show Headers at startUp, 1st call, correctly executed, no warning log message!
                .setDisplayHeadersAtStartUp(true)
                .setStickyHeaders(true)
                // Simulate developer 2nd call mistake, now it's safe, not executed, no warning log message!
                .setDisplayHeadersAtStartUp(true)
                // Simulate developer 3rd call mistake, still safe, not executed, warning log message displayed!
                .showAllHeaders();
        
    }
}

Can you please explain to me in short why i'm having to problem mentioned in the title?

Thank you

@royhenengel
Copy link
Author

Also noticed that after scrolling down, when scrolling back up, the section are missing.
1l0vh5

@davideas
Copy link
Owner

davideas commented Mar 8, 2017

@henengel, thank you for your congratulations!
So coming to your configuration, the equals method doesn't check the uniqueness as they should do. itemType value will be repeated in several items, this will cause not finding all items in java.util.List. If you don't have an ID, use default java implementation.
Try this first.

Then, the item web should also belongs to the same section, you need to add section as well. I don't remember well now, but if there are gaps stickyHeader will not work well. If so you should add section to it.

As last thing, mResults now is ok for only for testsing, but you must pass a copy to the Adapter once you will load the list from DB or remote.

@royhenengel
Copy link
Author

royhenengel commented Mar 10, 2017

@davideas Thank you for your time and reply.
As for the problem I mentioned in this ticket, the issue was indeed the ID.
Giving each item a unique ID solved the problem.
Now I went on and started to implement FlexibleAdapter in my real project.
Doing so, I encountered 2 new issues.

  1. I'm trying to set an animation on scroll (identical to your on scroll animation in Headers and Section in your sample app). As you did in your app I set setAnimationOnScrolling(true), and passed in the setItemAnimator method a new DefaultItemAnimator.
    In the VH I overrode scrollAnimators, as said in the wiki pages, and returned like in your app:
    AnimatorHelper.slideInFromLeftAnimator(animators, itemView, mAdapter.getRecyclerView(), 0.5f);
    After doing all of this, animations are still not working.

  2. When opening the Section pressed, A new RecyclerView is created with the relevant items for that Section. After closing the Section RecyclerView, returning to the main RecyclerView, and then opening again the same Section, 2 sticky headers are displayed instead of one.

I would very much appreciate your input.

The relevant code:

Main RecyclerView (where I tried to add onScrollAnimation):

    public class MainFeedFragment extends Fragment {

    /**
     * Constants
     */
    public static final String TAG = "MainFeedFragment";

    /**
     * General Obj
     */
    private Context mContext;
    private DataUtils mDataUtils;
    private RecyclerView mRecyclerView;
    private FlexibleAdapter<AbstractItem> mAdapter;
    private ArrayList<AbstractItem> mResults;
    private GeneralUtils mGeneralUtils;
    private AnalyticsUtils mAnalyticsUtils;


    /**
     * ===========
     * Constructor
     * ===========
     */
    public static MainFeedFragment newInstance(Context context, ArrayList<AbstractItem> results) {
        MainFeedFragment fragment = new MainFeedFragment();
        fragment.mContext = context;
        fragment.mResults = results;
        fragment.mGeneralUtils = GeneralUtils.getInstance();
        fragment.mAnalyticsUtils = AnalyticsUtils.getInstance();
        fragment.mDataUtils = DataUtils.getInstance();
        return fragment;
    }


    /**
     * =================
     * Lifecycle methods
     * =================
     */

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        /* Create rootView */
        View rootView = inflater.inflate(R.layout.fragment_main_feed, container, false);

        /* Init main feed */
        initFeed(rootView);

        /* Send screen name to analytics */
        mAnalyticsUtils.sendScreenTracker(AnalyticsScreenName.SCREEN_VIEW_FEED, mDataUtils.getGeneral().getMainFeedUrl());

        return rootView;
    }

    /**
     * ==============
     * Helper methods
     * ==============
     */

    private void initFeed(View rootView) {

        /* Get recyclerView from layout */
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerViewMain);

        /* Save views to cache to prevent reload of them*/
        mRecyclerView.setItemViewCacheSize(80);

        mRecyclerView.setHasFixedSize(true);

        /* Create the adapter */
        mAdapter = new FlexibleAdapter<>(mResults);

        /* Create pre cache layout manager to load views before displayed to user */
        PreCachingLayoutManager layoutManager = new PreCachingLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        /* Set the space of views that are not visible, to pre load them */
        layoutManager.setExtraLayoutSpace(mGeneralUtils.getScreenHeight(getActivity()));
        mRecyclerView.setLayoutManager(layoutManager);

        mAdapter.setAnimationOnScrolling(true);
        DefaultItemAnimator animator = new DefaultItemAnimator();
        mRecyclerView.setItemAnimator(animator);

        /* Set adapter */
        mRecyclerView.setAdapter(mAdapter);

        mAdapter.setDisplayHeadersAtStartUp(true).setStickyHeaders(true);
    }

    public void onDataChange(final ArrayList<AbstractItem> newResults) {
         /* Save scroll position */
        Parcelable recyclerViewState;
        recyclerViewState = mRecyclerView.getLayoutManager().onSaveInstanceState();

        /*mAdapter.onDataChanged(newResults);*/
        MyDiffUtil myDiffUtil = new MyDiffUtil(mResults, newResults);
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(myDiffUtil);
        mResults.clear();
        mResults.addAll(newResults);
        diffResult.dispatchUpdatesTo(mAdapter);

        /* Restore scroll position */
        mRecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);

        /* Set new results to default */
        mResults = newResults;
    }

    public RecyclerView getRecyclerView(){
        return this.mRecyclerView;
    }
 }

One of the VH that I overrode scrollAnimaor (all VH have the same override):

    public class SmallArticleViewHolder extends FlexibleViewHolder{

    public TextView title, subtitle, time;
    public ImageView feedArticleVideoButton, image, feedArticleCommentsIcon;
    public ImageButton feedArticleShareButton;
    public CustomTextView feedArticleCommentsNumber;
    public LinearLayout smallArticleRootView;

    public SmallArticleViewHolder(View convertView, FlexibleAdapter adapter) {
        super(convertView, adapter);
        this.image = (ImageView) convertView.findViewById(R.id.feedSmallArticleMainImage);
        this.title = (TextView) convertView.findViewById(R.id.feedSmallArticleTitle);
        this.subtitle = (TextView) convertView.findViewById(R.id.feedSmallArticleSubtitle);
        this.time = (TextView) convertView.findViewById(R.id.feedSmallArticleTime);
        this.feedArticleVideoButton = (ImageView) convertView.findViewById(R.id.feedSmallArticleVideoButton);
        this.feedArticleCommentsNumber = (CustomTextView) convertView.findViewById(R.id.feedSmallArticleCommentsNumber);
        this.feedArticleCommentsIcon = (ImageView) convertView.findViewById(R.id.feedSmallArticleCommentsIcon);
        this.feedArticleShareButton = (ImageButton) convertView.findViewById(R.id.feedSmallArticleShareButton);
        this.smallArticleRootView = (LinearLayout) convertView.findViewById(R.id.smallArticleRootView);
    }

    @Override
    public void scrollAnimators(@NonNull List<Animator> animators, int position, boolean isForward) {
        AnimatorHelper.slideInFromLeftAnimator(animators, itemView, mAdapter.getRecyclerView(), 0.5f);
    }
}

Section RecyclerView init (where 2 sticky headers are displayed when opening the same Section for the second time):

    public class SectionFeedFragment extends Fragment {
    /**
     * Constants
     */
    public static final String TAG = "SectionFeedFragment";

    /**
     * General Obj
     */
    private Context mContext;
    private RecyclerView mRecyclerView;
    private FlexibleAdapter mAdapter;
    private ArrayList<AbstractItem> mResults;
    private GeneralUtils mGeneralUtils;
    private AnalyticsUtils mAnalyticsUtils;
    private String mSectionUrl;


    /**
     * ===========
     * Constructor
     * ===========
     */
    public static SectionFeedFragment newInstance(Context context, ArrayList<AbstractItem> results, String sectionUrl) {
        SectionFeedFragment fragment = new SectionFeedFragment();
        fragment.mContext = context;
        fragment.mGeneralUtils = GeneralUtils.getInstance();
        fragment.mResults = results;
        fragment.mAnalyticsUtils = AnalyticsUtils.getInstance();
        fragment.mSectionUrl = sectionUrl;
        return fragment;
    }


    /**
     * =================
     * Lifecycle methods
     * =================
     */

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        /* Create rootView */
        View rootView = inflater.inflate(R.layout.fragment_section_feed, container, false);

        /* Init main feed */
        initFeed(rootView);

        /* Send screen name to analytics */
        mAnalyticsUtils.sendScreenTracker(AnalyticsScreenName.SCREEN_VIEW_FEED, mSectionUrl);

        return rootView;
    }


    /**
     * ==============
     * Helper methods
     * ==============
     */

    private void initFeed(View rootView) {

       /* Get recyclerView from layout */
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerViewSection);

        /* Save views to cache to prevent reload of them*/
        mRecyclerView.setItemViewCacheSize(80);

        mRecyclerView.setHasFixedSize(true);

        /* Create the adapter */
        mAdapter = new FlexibleAdapter<>(mResults);

        /* Create pre cache layout manager to load views before displayed to user */
        PreCachingLayoutManager layoutManager = new PreCachingLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        /* Set the space of views that are not visible, to pre load them */
        layoutManager.setExtraLayoutSpace(mGeneralUtils.getScreenHeight(getActivity()));
        mRecyclerView.setLayoutManager(layoutManager);

        /* Set adapter */
        mRecyclerView.setAdapter(mAdapter);

        mAdapter.setDisplayHeadersAtStartUp(true).setStickyHeaders(true);
    }

    public void onDataChange(ArrayList<AbstractItem> newResults) {

         /* Save scroll position */
        Parcelable recyclerViewState;
        recyclerViewState = mRecyclerView.getLayoutManager().onSaveInstanceState();

        /*mAdapter.onDataChanged(newResults);*/
        MyDiffUtil myDiffUtil = new MyDiffUtil(mResults, newResults);
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(myDiffUtil);
        mResults.clear();
        mResults.addAll(newResults);
        diffResult.dispatchUpdatesTo(mAdapter);

        /* Restore scroll position */
        mRecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);

        /* Set new results to default */
        mResults = newResults;
    }
}

A short video display of the sticky issue:
1l5kwb

If you need more information like the list created or anything else, I will be more then happy to provide you that.

Again thank you very much for your time and effort.

@davideas
Copy link
Owner

@henengel, about your first issue, I tried your exact order of configuration even from onCreate but to me it still works! I think, it is your special layout manager that preloads the VHs and it binds them.
However, initialize the adapter and RV in the onActivityCreated().

Then you don't need DiffUtil at all, just call mAdapter.updateDataSet(new list copy).

About your second issue, this seems much more complicated. I understood you create a new Fragment in the section you click?
Probably you need to modify more things. If you use multiple adapter simultaneously the adapter items must have another reference, while the model object can be the same, for this purpose I created the IHolder interface for the items.

But why you load another RV and so another adapter? can you create expandable items with subItems in it?

@royhenengel
Copy link
Author

@davideas About my first issue, you were correct. By changing the layout manager, the animation started to work.

As for my second issue:

I understood you create a new Fragment in the section you click?

You are correct.

If you use multiple adapters simultaneously the adapter items must have another reference, while the model object can be the same, for this purpose I created the IHolder interface for the items.

When you say "another reference", by creating another adapter, don't they get another reference?
(Forgive me for the noob question).

But why you load another RV and so another adapter? can you create expandable items with subItems in it?

In my case, every Section and it's few items represent a category with dedicated items in that category.
My customer wants that when a Section(Category) is pressed, a new screen (Fragment) with all of the category items (and not just a few like in the main fragment) will be displayed.

  1. Do you in mind a better way to achieve this? always willing and wanting to learn.
  2. Is there any other information I can provide to help you better understand the issue?
  3. Is there a way to contribute to you and your project to show my appreciation for your work, time and help?

Thank you

@royhenengel
Copy link
Author

@davideas Hi, I think I issue has something to do with the ID's.
For some reason the Section gets a new ID when opening it for the second time hence resulting in 2 Sections.
I will keep going over the issue and of course update here for anyone else once the issue is solved.
I would still like to make a donation, so waiting on your reply.
Thank you.

@davideas
Copy link
Owner

davideas commented Mar 13, 2017

When you say "another reference", by creating another adapter, don't they get another reference?

I mean another adapter item reference, each adapter displayed simultaneously should have items with their own flags.

  1. Do you in mind a better way to achieve this? always willing and wanting to learn.

I see 2 ways, now you display a big item with a fragment in it with another recyclerview in it. One solution is to use the category as expandable that contains subitems, you start with all items collapsed. Another solution is to open a new activity from a side that enters as a subfolder as Dropbox is doing.

  1. Is there any other information I can provide to help you better understand the issue?

For the moment, you need to review your architecture because it looks complicated and 2 adapters add another level of complex.

  1. Is there a way to contribute...

Well, it is certainly nice from your side, actually when I started this project was I did not thought at it took this success. I have to think at it.
However you can always contribute by completing or add new features or test something. There's data-binding branch ready to be tested, I am not very familiar with it, maybe you can have a look.

@royhenengel
Copy link
Author

royhenengel commented Mar 14, 2017

@davideas Fixing the id's didn't solve the issue.

I mean another adapter item reference, each adapter displayed simultaneously should have items with their own flags.

If I understand correctly this is already implemented.
When creating a Section fragment, a new adapter with new item references is created.

Can you elaborate on the Iholder interface?
Should my Abstract flexible item implement it? Or only
AbstractHeaderItem/
AbstractItem implements
ISectionable<BigArticleViewHolder, SectionItem>.
What should I return/pass as the model?

@royhenengel
Copy link
Author

@davideas After debugging a bit, I found that the double Header item is probably a result of not preparing the data for the adapter properly.
I will try to explain the whole flow and attach my code.
Work flow:
Every time a Section/Header is clicked, a request is sent to a server to get all the relevant items for that Section.

  • When getting back the response, the first item of the response is always the Section/Header clicked, followed by the relevant items of that section.
  • I check if the Section feed info is a result of refreshing the data of the original feed (same section id) or if the response contains data of another feed (a new feed was clicked and a new Section feed needs to be created)
  • After that, I create in code the relevant items from the response and pass the whole dataset to the Section adapter (not the main feed adapter).

Reproduce the issue:
When clicking for the first time on a Section/Header, when creating the feed for the first time, everything works OK.
The problem starts when clicking the same Section/Header for the second or third time.
In theory, the first item of the section should always be a item, and not a header.
after clicking the same Section/Header for the second or third time (not consistent), I can't seem to understand why, the first item if the dataset is a Section/Header item, causing the problem.

Relevant code:

    private void parsDataResultsForSectionFeed(final String response, final VolleyOnFeedDataSuccessCallback callback) {

        /* Create a new object that contains a list of gson array's */
        mGsonResults = mGsonParser.fromJson(response, ItemObjectResults.class);

        /* If SectionId equals null, this SectionFeed is created for the first time.
        *  If SectionId equals SectionId from response, try and update current Section, else
        *  create a new SectionFeed from response */
        if (mSectionId != null
                && mSectionId.equals(mGsonResults.getSectionId())) {
            /* If saved last updated id equals the one from response, the data of this SectionFeed
             * wasn't changed, and return, else update the data */
            if (mLastUpdatedSection != mGsonResults.getLastUpdated()) {
                /* Parse gson array's to an ArrayList */
                mResultsSection = parseResultsToItems(mGsonResults.getItems(), false);
                /* Get taboola items */
                mAdsUtils.getTaboolaFromServerForFeed(mResultsSection, mNumberOfTaboolaItems, new VolleyOnTaboolaSuccessCallback() {
                    @Override
                    public void onTaboolaSuccess() {
                        mResultsSection = mAdsUtils.getResults();
                        callback.onFeedDataSuccess(mResultsSection, true);
                    }
                });

                /* Set current section id */
                mSectionId = mGsonResults.getSectionId();

                /* Update last updated id */
                mLastUpdatedSection = mGsonResults.getLastUpdated();

            } else {
                /* Feed data wasn't updated, return */
                callback.onFeedDataSuccess(mResultsSection, false);
            }

        } else {
            /* Create Feed for the first time */
            /* Parse gson array's to an ArrayList */
            mResultsSection = parseResultsToItems(mGsonResults.getItems(), false);

            mAdsUtils.getTaboolaFromServerForFeed(mResultsSection, mNumberOfTaboolaItems, new VolleyOnTaboolaSuccessCallback() {
                @Override
                public void onTaboolaSuccess() {
                    mResultsSection = mAdsUtils.getResults();
                    callback.onFeedDataSuccess(mResultsSection, true);
                }
            });

            /* Set current section id */
            mSectionId = mGsonResults.getSectionId();

            /* Update last updated */
            mLastUpdatedSection = mGsonResults.getLastUpdated();
        }
    }
    private ArrayList<AbstractItem> parseResultsToItems(List<Item> gsonResults, boolean showSectionArrow) {

        /** =============================================================================================
         * BigArticleItem(itemType, name, title, subtitle, pubDate, wapLink, finalUrl, imageUrl,
         *             hasVideo, hasComments, itemCategoryColor, comments, categoryId, targetingCategory)
         *
         *  SmallArticleItem(itemType, name, title, subtitle, pubDate, wapLink, finalUrl, imageUrl,
         *             hasVideo, hasComments, itemCategoryColor, comments, categoryId, targetingCategory)
         *
         *  WebItem(itemType, wvUrl, wvWidth, wvHeight)
         *
         *  SectionItem(itemType, name, color, finalUrl, url, categoryId, targetingUrl, title, subtitle)
         *
         *  UrlBannerItem(itemType, type, iu, width, height)
         *
         *  XmlBannerItem(itemType, type, iu, width, height)
         *
         *  TaboolaItem(itemType, title, pubDate, imageUrl, finalUrl, itemResponseId)
         * ============================================================================================== */

        ArrayList<AbstractItem> items = new ArrayList<>();
        SectionItem currentSection = null;

        for (int i = 0; i < gsonResults.size(); i++) {
            Item itemObject = gsonResults.get(i);
            if (itemObject.getItemType().equals("ARTICLE - big")) {
                BigArticleItem item = new BigArticleItem(mContext, currentSection, itemObject.getItemId(), itemObject.getItemType(), itemObject.getName(), itemObject.getTitle(), itemObject.getSubtitle(),
                        itemObject.getPubDate(), itemObject.getWapLink(), itemObject.getFinaleUrl(), itemObject.getImage(), itemObject.getHasVideo(),
                        itemObject.getHasComments(), itemObject.getItemCategoryColor(), itemObject.getComments(), itemObject.getCategoryID(),
                        itemObject.getTargetingCategory(), itemObject.getArticleID());
                items.add(item);

            } else if (itemObject.getItemType().equals("ARTICLE")) {
                SmallArticleItem item = new SmallArticleItem(mContext, currentSection, itemObject.getItemId(), itemObject.getItemType(), itemObject.getName(), itemObject.getTitle(), itemObject.getSubtitle(),
                        itemObject.getPubDate(), itemObject.getWapLink(), itemObject.getFinaleUrl(), itemObject.getImage(), itemObject.getHasVideo(),
                        itemObject.getHasComments(), itemObject.getItemCategoryColor(), itemObject.getComments(), itemObject.getCategoryID(),
                        itemObject.getTargetingCategory(), itemObject.getArticleID());
                items.add(item);

            } else if (itemObject.getItemType().equals("web")) {
                WebViewItem item = new WebViewItem(currentSection, itemObject.getItemId(), itemObject.getItemType(), itemObject.getWvUrl(), itemObject.getWvWidth(), itemObject.getWvHeight());
                items.add(item);

            } else if (itemObject.getItemType().equals("sectionTitle")) {
                if (showSectionArrow == false) {
                    SectionItem item = new SectionItem(itemObject.getItemId(), itemObject.getItemType(), itemObject.getName(), itemObject.getColor(), itemObject.getFinaleUrl(), itemObject.getUrl(),
                            itemObject.getCategoryID(), itemObject.getTargetingCategory(), itemObject.getTitle(), itemObject.getSubtitle(), false);
                    currentSection = item;
                } else if (showSectionArrow == true) {
                    SectionItem item = new SectionItem(itemObject.getItemId(), itemObject.getItemType(), itemObject.getName(), itemObject.getColor(), itemObject.getFinaleUrl(), itemObject.getUrl(),
                            itemObject.getCategoryID(), itemObject.getTargetingCategory(), itemObject.getTitle(), itemObject.getSubtitle(), true);
                    currentSection = item;
                }

            } else if (itemObject.getItemType().equals("banner") && itemObject.getType().equals("url")) {
                UrlBannerItem item = new UrlBannerItem(mContext, currentSection, itemObject.getItemId(), itemObject.getItemType(), itemObject.getType(), itemObject.getIu(), itemObject.getWidth(), itemObject.getHeight());
                items.add(item);

            } else if (itemObject.getItemType().equals("banner") && itemObject.getType().equals("xml")) {
                XmlBannerItem item = new XmlBannerItem(mContext, currentSection, itemObject.getItemId(), itemObject.getItemType(), itemObject.getType(), itemObject.getIu(), itemObject.getWidth(), itemObject.getHeight());
                items.add(item);

            } else if (itemObject.getItemType().equals("taboola")) {
                TaboolaItem item = new TaboolaItem(mContext, currentSection, itemObject.getItemId(), itemObject.getItemType(), itemObject.getTaboolaPublisherName(), itemObject.getTitle(), itemObject.getPubDate(), itemObject.getImage(), itemObject.getFinaleUrl(),
                        itemObject.getTaboolaItemResponseId());
                items.add(item);
                mNumberOfTaboolaItems++;
            }
        }

        return items;
    }

Dataset when creating the dataset for the first time:
2017-03-15_07-58-15

Dataset when clicking the same Section/Header for the second/third time:
2017-03-15_07-59-00

@royhenengel
Copy link
Author

@davideas Hi, it's been a while since we last communicated.
In the meantime, I managed to fix the issue (not a proper one but it will do until you give me your input and/or fix the issue if there is one).
I simply added a method in the Section/Header fragments that checks of the first item of the dataset is an instance of SectionItem, and if so then remove it.
Also, as to your offer, I stopped using DiffUtil and starting updating the dataset using your method
mAdapter.updateDataSet(newResults, true);.
Unfortunately, there seems to be an issue with it (not sure if its because of wrong implementation on my side, or a bug).
When updating the dataset, using your method refreshes items, even if they are the same, resulting in unnecessary updates.
When using DiffUtils I didn't have this problem.
Because I have DFP banners items in my dataset, when they refresh they don't reload properly.
Since they are always the same (unless one was added), DiffUtill wouldn't update them, while your method causes issues.
I hope to hear from you and solve all open issues mentioned in the ticket.

@royhenengel
Copy link
Author

@davideas Hi is everything OK? you haven't responded in a while...

@davideas
Copy link
Owner

@davideas Hi is everything OK? you haven't responded in a while...

Sorry @henengel, got other stuff more urgent to do in real life :-) everything is ok, by the way!

@royhenengel
Copy link
Author

LOL, I'm sure you have!!!
For some of us, this adapter is the real life :).
I don't mean to bother you, It's just that my app launches in a couple of days, and I would like very much to use your adapter in it, though currently, I can't unfortunately.
That's why I tried you again.
To most of the issues in this ticket, I managed to find a workaround, except for one (I opened a new ticket about it since it is not directly linked to this one.)
To the issue, I will make it short to not waste your time.
When using your method to update the data set, the items that are the same and have not changed, are reloaded/ refreshed.
Is there a way to exclude some item types from update data set?
Because of this issue I tried using Diffutils because there I have more control over what is updated, but when using the approach, after dispatching the updates to the adapter, all Section/header item disappear.
Thank you

@davideas
Copy link
Owner

davideas commented Mar 22, 2017

@henengel Ok, for the update issue, I gave you a possible solution in the new issue (#321).

This was referenced Mar 22, 2017
@davideas davideas closed this as completed Apr 5, 2017
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants