How to fill title and grid layouts with the next page "10 items"

Viewed 198

In my app I have four layouts, "Card List" , "Card Magazine" , "Title" and "Grid", I make option menu to allow the users to change it from the Option Menu "change the layout", the problem happening here is when running the app first time with choosing Title or Grid layout, it's show the only first page "10 items" the result come from retrofit call

enter image description here

To relate see this question

in old version of this app "When I used activity" I solved this problem with this lines of code on Title and Grid Viewholder

if(position == getItemCount() -1)

if(context instanceof MainActivity){
 ((MainActivity)context).getMainPagePosts();

}

but in this version I using fragments, so when I tried to thinking to solve it I created interface called "WhichFragmentCalled" and give it the fragment and viewHolder as a parameters

public interface WhichFragmentCalled {

     void whichFragmentAndViewModel(Fragment fragment, PostViewModel postViewModel);
}

Then I used it in adapter and fragment like this

 @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        WhichFragmentCalled whichFragmentCalled = adapter;

        whichFragmentCalled.whichFragmentAndViewModel(this,postViewModel);
    }

and make the adapter implement this interface, here's the full PostAdapter code

public class PostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements WhichFragmentCalled{
    private Context context;
    private List<Item> items;

    private static final int CARD = 0;
    private static final int CARD_MAGAZINE = 1;
    private static final int TITLE = 2;
    private static final int GRID = 3;
    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
    public static final String TAG = "POST ADAPTER";

    private int viewType;
    private int position;
    private Fragment fragment;
    private PostViewModel postViewModel;

    public PostAdapter(Context context, List<Item> items) {
        this.context = context;
        this.items = items;
    }

    public void setViewType(int viewType) {
        this.viewType = viewType;
        notifyDataSetChanged();
    }

    public int getViewType() {
        return this.viewType;
    }


    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View view;

        if (this.viewType == CARD) {
            view = inflater.inflate(R.layout.card, parent, false);
            return new CardViewHolder(view);
        } else if (this.viewType == CARD_MAGAZINE) {
            view = inflater.inflate(R.layout.card_magazine, parent, false);
            return new CardMagazineViewHolder(view);
        } else if (this.viewType == TITLE) {
            if(SDK_VERSION < Build.VERSION_CODES.LOLLIPOP){
                view = inflater.inflate(R.layout.title_layout_v15,parent,false);
            }else {
                view = inflater.inflate(R.layout.title_layout, parent, false);
            }
            return new TitleViewHolder(view);
        } else {
            if(SDK_VERSION < Build.VERSION_CODES.LOLLIPOP){
                view = inflater.inflate(R.layout.grid_layout_v15,parent,false);
            }else {
                view = inflater.inflate(R.layout.grid_layout, parent, false);
            }
            return new GridViewHolder(view);
        }

    }


    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {


        this.position = position;


        int itemType = getViewType();
        Item item = items.get(holder.getAdapterPosition());
        final Document document = Jsoup.parse(item.getContent());
        final Elements elements = document.select("img");

//        Log.e("IMAGE", document.getAllElements().select("img").get(0).attr("src"));

        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat
                ("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
        Intent intent = new Intent(context, DetailsActivity.class);

        switch (itemType) {
            case CARD:
                if (holder instanceof CardViewHolder) {
                    CardViewHolder cardViewHolder = (CardViewHolder) holder;
                    cardViewHolder.postTitle.setText(item.getTitle());

                    try {
                        Log.e("IMAGE", elements.get(0).attr("src"));
                        Glide.with(context).load(elements.get(0).attr("src"))
                                .into(cardViewHolder.postImage);
                    }catch (IndexOutOfBoundsException e){
                        cardViewHolder.postImage.setImageResource(R.mipmap.ic_launcher);
                        Log.e(TAG,e.toString());
                    }


                    cardViewHolder.postDescription.setText(document.text());
                    try {
                        date = format.parse(items.get(position).getPublished());

                    } catch (ParseException e) {
                        e.printStackTrace();
                    }

                    PrettyTime prettyTime = new PrettyTime();

                    cardViewHolder.postDate.setText(prettyTime.format(date));

                    cardViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {


                            intent.putExtra("url", item.getUrl());
                            intent.putExtra("title", item.getTitle());
                            intent.putExtra("content", item.getContent());
                            int youtubeThumbnailImagesetVisibility = 0;

                            Element element = document.body();

                            String youtubeThumbnailImageSrc = "";
                            String youTubeLink = "";
                            for (Element e : element.getElementsByClass
                                    ("YOUTUBE-iframe-video")) {
                                youtubeThumbnailImageSrc = e.attr("data-thumbnail-src");
                                youTubeLink = e.attr("src");
                                Log.e("YouTube thumbnail", youtubeThumbnailImageSrc);
                                Log.e("Youtube link", youTubeLink);
                            }

                            if (youtubeThumbnailImageSrc.isEmpty()) {
                                youtubeThumbnailImagesetVisibility = 8;
                                intent.putExtra("youtubeThumbnailImagesetVisibility",
                                        youtubeThumbnailImagesetVisibility);
                            } else {
                                intent.putExtra("youtubeThumbnailImageSrc", youtubeThumbnailImageSrc);
                                intent.putExtra("youTubeLink", youTubeLink);
                            }

//             String imageSrc = elements.get(0).attr("src");
//             intent.putExtra("blogImage",imageSrc);

                            view.getContext().startActivity(intent);
                        }
                    });
                }
                break;

            case CARD_MAGAZINE:
                if (holder instanceof CardMagazineViewHolder) {
                    CardMagazineViewHolder cardMagazineViewHolder = (CardMagazineViewHolder) holder;
                    cardMagazineViewHolder.postTitle.setText(item.getTitle());


                    try {
                        Log.e("IMAGE", elements.get(0).attr("src"));
                        Glide.with(context).load(elements.get(0).attr("src"))
                                .into(cardMagazineViewHolder.postImage);
                    }catch (IndexOutOfBoundsException e){
                        cardMagazineViewHolder.postImage.setImageResource(R.mipmap.ic_launcher);
                        Log.e(TAG,e.toString());
                    }

                    try {
                        date = format.parse(items.get(position).getPublished());

                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    PrettyTime prettyTime = new PrettyTime();

                    cardMagazineViewHolder.postDate.setText(prettyTime.format(date));

                    cardMagazineViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            intent.putExtra("url", item.getUrl());
                            intent.putExtra("title", item.getTitle());
                            intent.putExtra("content", item.getContent());
                            int youtubeThumbnailImagesetVisibility = 0;

                            Element element = document.body();

                            String youtubeThumbnailImageSrc = "";
                            String youTubeLink = "";
                            for (Element e : element.getElementsByClass
                                    ("YOUTUBE-iframe-video")) {
                                youtubeThumbnailImageSrc = e.attr("data-thumbnail-src");
                                youTubeLink = e.attr("src");
                                Log.e("YouTube thumbnail", youtubeThumbnailImageSrc);
                                Log.e("Youtube link", youTubeLink);
                            }

                            if (youtubeThumbnailImageSrc.isEmpty()) {
                                youtubeThumbnailImagesetVisibility = 8;
                                intent.putExtra("youtubeThumbnailImagesetVisibility",
                                        youtubeThumbnailImagesetVisibility);
                            } else {
                                intent.putExtra("youtubeThumbnailImageSrc", youtubeThumbnailImageSrc);
                                intent.putExtra("youTubeLink", youTubeLink);
                            }

//             String imageSrc = elements.get(0).attr("src");
//             intent.putExtra("blogImage",imageSrc);

                            view.getContext().startActivity(intent);
                        }
                    });
                }
                break;
            case TITLE:
                if (holder instanceof TitleViewHolder) {
                    TitleViewHolder titleViewHolder = (TitleViewHolder) holder;
                    titleViewHolder.postTitle.setText(item.getTitle());

                    Log.d("TITLE", "title layout called");


                    try {
                        Log.e("IMAGE", elements.get(0).attr("src"));
                        Glide.with(context).load(elements.get(0).attr("src"))
                                .into(titleViewHolder.postImage);
                    }catch (IndexOutOfBoundsException e){
                        titleViewHolder.postImage.setImageResource(R.mipmap.ic_launcher);
                        Log.e(TAG,e.toString());
                    }


                    titleViewHolder.itemView.setOnClickListener(view -> {
                        intent.putExtra("url", item.getUrl());
                        intent.putExtra("title", item.getTitle());
                        intent.putExtra("content", item.getContent());
                        int youtubeThumbnailImagesetVisibility = 0;

                        Element element = document.body();

                        String youtubeThumbnailImageSrc = "";
                        String youTubeLink = "";
                        for (Element e : element.getElementsByClass
                                ("YOUTUBE-iframe-video")) {
                            youtubeThumbnailImageSrc = e.attr("data-thumbnail-src");
                            youTubeLink = e.attr("src");
                            Log.e("YouTube thumbnail", youtubeThumbnailImageSrc);
                            Log.e("Youtube link", youTubeLink);
                        }

                        if (youtubeThumbnailImageSrc.isEmpty()) {
                            youtubeThumbnailImagesetVisibility = 8;
                            intent.putExtra("youtubeThumbnailImagesetVisibility",
                                    youtubeThumbnailImagesetVisibility);
                        } else {
                            intent.putExtra("youtubeThumbnailImageSrc", youtubeThumbnailImageSrc);
                            intent.putExtra("youTubeLink", youTubeLink);
                        }

//             String imageSrc = elements.get(0).attr("src");
//             intent.putExtra("blogImage",imageSrc);

                        view.getContext().startActivity(intent);
                    });

                }
                break;
            case GRID:
                if (holder instanceof GridViewHolder) {
                    GridViewHolder gridViewHolder = (GridViewHolder) holder;
                    gridViewHolder.postTitle.setText(item.getTitle());


                    try {
                        Log.e("IMAGE", elements.get(0).attr("src"));
                        Glide.with(context).load(elements.get(0).attr("src"))
                                .into(gridViewHolder.postImage);
                    }catch (IndexOutOfBoundsException e){
                        gridViewHolder.postImage.setImageResource(R.mipmap.ic_launcher);
                        Log.e(TAG,e.toString());
                    }



                    gridViewHolder.itemView.setOnClickListener(view -> {
                        intent.putExtra("url", item.getUrl());
                        intent.putExtra("title", item.getTitle());
                        intent.putExtra("content", item.getContent());
                        int youtubeThumbnailImagesetVisibility;

                        Element element = document.body();

                        String youtubeThumbnailImageSrc = "";
                        String youTubeLink = "";
                        for (Element e : element.getElementsByClass
                                ("YOUTUBE-iframe-video")) {
                            youtubeThumbnailImageSrc = e.attr("data-thumbnail-src");
                            youTubeLink = e.attr("src");
                            Log.e("YouTube thumbnail", youtubeThumbnailImageSrc);
                            Log.e("Youtube link", youTubeLink);
                        }

                        if (youtubeThumbnailImageSrc.isEmpty()) {
                            youtubeThumbnailImagesetVisibility = 8;
                            intent.putExtra("youtubeThumbnailImagesetVisibility",
                                    youtubeThumbnailImagesetVisibility);
                        } else {
                            intent.putExtra("youtubeThumbnailImageSrc", youtubeThumbnailImageSrc);
                            intent.putExtra("youTubeLink", youTubeLink);
                        }

//             String imageSrc = elements.get(0).attr("src");
//             intent.putExtra("blogImage",imageSrc);

                        view.getContext().startActivity(intent);
                    });
                }
        }
    }


    @Override
    public int getItemCount() {
        return items.size();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public void whichFragmentAndViewModel(Fragment fragment, PostViewModel postViewModel) {
        this.fragment = fragment;
        this.postViewModel = postViewModel;

        if(position == getItemCount() -1) {
           postViewModel.getPosts();
           notifyDataSetChanged();
        }
    }


    public class CardViewHolder extends RecyclerView.ViewHolder {

        ImageView postImage;
        TextView postTitle,postDescription, postDate;

        private CardViewHolder(View itemView) {
            super(itemView);
            postImage = itemView.findViewById(R.id.postImage);
            postTitle = itemView.findViewById(R.id.postTitle);
            postDescription = itemView.findViewById(R.id.postDescription);
            postDate = itemView.findViewById(R.id.postDate);

        }
    }

    public class CardMagazineViewHolder extends RecyclerView.ViewHolder {

        ImageView postImage;
        TextView postTitle, postDate;

        private CardMagazineViewHolder(View itemView) {
            super(itemView);
            postImage = itemView.findViewById(R.id.postImage);
            postTitle = itemView.findViewById(R.id.postTitle);
            postDate = itemView.findViewById(R.id.postDate);

        }
    }

    public class TitleViewHolder extends RecyclerView.ViewHolder {
        TextView postTitle;
        MyImageview postImage;


        private TitleViewHolder(@NonNull View itemView) {
            super(itemView);
            postTitle = itemView.findViewById(R.id.postTitle);
            postImage = itemView.findViewById(R.id.postImage);
        }
    }


    public class GridViewHolder extends RecyclerView.ViewHolder {
        TextView postTitle;
        MyImageview postImage;


        private GridViewHolder(@NonNull View itemView) {
            super(itemView);
            postTitle = itemView.findViewById(R.id.postTitle);
            postImage = itemView.findViewById(R.id.postImage);
        }
    }
}

now this code work only when I switch from the title or grid layout to others layout and back to it again, I think the onBindViewHolder not detect this implement of interface at the first time, so the challenge is How to move the implement of this interface insede onBindViewHolder method

 @Override
    public void whichFragmentAndViewModel(Fragment fragment, PostViewModel postViewModel) {
        this.fragment = fragment;
        this.postViewModel = postViewModel;

        if(position == getItemCount() -1) {
           postViewModel.getPosts();
           notifyDataSetChanged();
        }
    }

This how I use the change layout in fragments, I removed unrelated with question codes

HomeFragment class

private PostViewModel postViewModel;
    public static final String TAG = "HomeFragment";
    private RecyclerView recyclerView;
    private PostAdapter adapter;
    private List<Item> itemArrayList;

    private boolean isScrolling = false;
    private int currentItems, totalItems, scrollOutItems;
    private GridLayoutManager titleLayoutManager, gridLayoutManager;
    WrapContentLinearLayoutManager layoutManager;


    private SharedPreferences sharedPreferences;

    public ItemsDatabase itemsDatabase;

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

        postViewModel = new ViewModelProvider(this).get(PostViewModel.class);

        itemsDatabase = ItemsDatabase.getINSTANCE(getContext());

        postViewModel.finalURL.setValue(PostsClient.getBaseUrl() + "?key=" + PostsClient.getKEY() );

        postViewModel.getPosts();

        View root = inflater.inflate(R.layout.fragment_home, container, false);

        setHasOptionsMenu(true);

        itemArrayList = new ArrayList<>();

        recyclerView = root.findViewById(R.id.homeRecyclerView);
        adapter = new PostAdapter(getContext(),itemArrayList);


        layoutManager = new WrapContentLinearLayoutManager(getContext(),
                LinearLayoutManager.VERTICAL, false);
        titleLayoutManager = new GridLayoutManager(getContext(), 2);
        gridLayoutManager = new GridLayoutManager(getContext(), 3);

        sharedPreferences =  getContext().getSharedPreferences("settings", Context.MODE_PRIVATE);
        String layout = sharedPreferences.getString("recyclerViewLayout", "cardLayout");
        switch (layout) {
            case "cardLayout":
                recyclerView.setLayoutManager(layoutManager);
                adapter.setViewType(0);
                recyclerView.setAdapter(adapter);
                break;
            case "cardMagazineLayout":
                recyclerView.setLayoutManager(layoutManager);
                adapter.setViewType(1);
                recyclerView.setAdapter(adapter);
                break;
            case "titleLayout":
                recyclerView.setLayoutManager(titleLayoutManager);
                adapter.setViewType(2);
                recyclerView.setAdapter(adapter);
                adapter.whichFragmentAndViewModel(this,postViewModel);
                break;
            case "gridLayout":
                recyclerView.setLayoutManager(gridLayoutManager);
                adapter.setViewType(3);
                recyclerView.setAdapter(adapter);
                adapter.whichFragmentAndViewModel(this,postViewModel);


        }


        recyclerView.setAdapter(adapter);

  recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                    isScrolling = true;



            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0) {
                    if(layout.equals("cardLayout") || layout.equals("cardMagazineLayout")) {
                        currentItems = layoutManager.getChildCount();
                        totalItems = layoutManager.getItemCount();
                        scrollOutItems = layoutManager.findFirstVisibleItemPosition();
                    }else if(layout.equals("titleLayout")){
                        currentItems = titleLayoutManager.getChildCount();
                        totalItems = titleLayoutManager.getItemCount();
                        scrollOutItems = titleLayoutManager.findFirstCompletelyVisibleItemPosition();
                    }else {
                        currentItems = gridLayoutManager.getChildCount();
                        totalItems = gridLayoutManager.getItemCount();
                        scrollOutItems = gridLayoutManager.findFirstCompletelyVisibleItemPosition();
                    }
                    if (isScrolling && (currentItems + scrollOutItems == totalItems)) {
                        isScrolling = false;
                        postViewModel.getPosts();
//                        adapter.notifyDataSetChanged();


                    }
                }

            }
        });


        return root;

    }

    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        //Empty the old menu
//        if(menu.hasVisibleItems()){
//            menu.clear();
//        }
        inflater.inflate(R.menu.main, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {

        if (item.getItemId() == R.id.change_layout) {
            android.app.AlertDialog.Builder builder
                    = new android.app.AlertDialog.Builder(getContext());

            builder.setTitle(getString(R.string.choose_layout));

            String[] recyclerViewLayouts = getResources().getStringArray(R.array.RecyclerViewLayouts);
            SharedPreferences.Editor editor = sharedPreferences.edit();


            builder.setItems(recyclerViewLayouts, (dialog, index) -> {
                switch (index) {
                    case 0: // Card List Layout
                        adapter.setViewType(0);
                        recyclerView.setLayoutManager(layoutManager);
                        recyclerView.setAdapter(adapter);
                        editor.putString("recyclerViewLayout", "cardLayout");
                        editor.apply();
                        break;
                    case 1: // Cards Magazine Layout
                        adapter.setViewType(1);
                        recyclerView.setLayoutManager(layoutManager);
                        recyclerView.setAdapter(adapter);
                        editor.putString("recyclerViewLayout", "cardMagazineLayout");
                        editor.apply();
                        break;
                    case 2: // PostTitle Layout
                        adapter.setViewType(2);
                        recyclerView.setLayoutManager(titleLayoutManager);
                        recyclerView.setAdapter(adapter);
                        editor.putString("recyclerViewLayout", "titleLayout");
                        editor.apply();
                        break;
                    case 3: //Grid Layout
                        adapter.setViewType(3);
                        recyclerView.setLayoutManager(gridLayoutManager);
                        recyclerView.setAdapter(adapter);
                        editor.putString("recyclerViewLayout", "gridLayout");
                        editor.apply();

                }
            });

            android.app.AlertDialog alertDialog = builder.create();
            alertDialog.show();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        WhichFragmentCalled whichFragmentCalled = adapter;

        whichFragmentCalled.whichFragmentAndViewModel(this,postViewModel);
    }
}
1 Answers

This is more of a suggestion than an answer, but if you are going to use the ViewModel, I strongly suggest that you move all the business logic (pretty much anything non-ui related), and move it inside your viewmodel. You can read more about MVVM architecture from the android site.

As for your actual question, if you are showing only 10 objects, then it sounds like your data list only has 10 objects - so I suggest validating the data list you are receiving from retrofit, and then validate it while it's passing to your adapter. Logs and/or breakpoints will help you.

Also, for simplicity of my explanation, I would move all of the code in onCreateView() that comes after the setHasOptionsMenu(true); and move it into onViewCreated() so you don't accidentally have null views. I would then move all your adapter/recyclerview logic into onResume() so that the lists/ui are properly restored on configuration/state changes.

If PostAdapter is being used for all the different layouts, then there is no need for your interface. You would only need one Fragment class, one ViewModel, and one RecyclerView.Adapter, because if I understand it correctly, you are using the same list of objects, so you really only need to focus on changing the views/layouts for the adapter.

To change layouts:

  1. invalidate your current visible list in the recycler view, by setting the reference to your adapter to null. recyclerView.setAdapter(null);
  2. Create a new instance of your adapter, if you have your data set saved in your viewmodel, you can just pass that to your new adapter, instead of fetching more objects from retrofit.
  3. then, set the new adapter back to the recyclerView, and apply the appropriate LayoutManager for the situation.

postViewModel.getPosts(); - if this is loading post objects from retrofit, then this is another potential bug because retrofit is generally asynchronous, and it doesn't look like you have any conditional checks to make sure your list is ready before passing it to the adapter. You can easily solve this problem with Androids LiveData objects. They're amazing and are perfect for your use case.

Related