1

I have a list of products in a recycler view. once an item is pressed it will take u to the second activity to show more info related to that product. I'm trying to implement viewPager. was following a tutorial from CodingWithMitch but in his example, he has random data and could easily fetch them.

ArrayList<Fragment> fragments = new ArrayList<>();
    Hat[] hats = Hats.getHats();
    for(Hat hat: hats){
        ViewPagerItemFragment fragment = ViewPagerItemFragment.getInstance(hat);
        fragments.add(fragment);
    }
    MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);
    mMyViewPager.setAdapter(pagerAdapter);
    mTabLayout.setupWithViewPager(mMyViewPager, true);

Unfortunately, for me, the data r fetched from Livedata object. How do I loop or iterate over the livedata to extract all the products object so I can set the fragments!

ArrayList<Fragment> fragments = new ArrayList<>();
    final MarketViewModel marketViewModel = new ViewModelProvider(this).get(MarketViewModel.class);
    MutableLiveData<List<Product>> products = marketViewModel.getProductInfo("parentID");
    //What to do here !!!
    /*for (:) {
        ProductInfoFragment fragment = ProductInfoFragment.getInstance(products);
        fragments.add(fragment);
    }*/
    ProductPagerAdapter adapter = new ProductPagerAdapter(getSupportFragmentManager(), 0, fragments);
    viewPager.setAdapter(adapter);
    tabLayout.setupWithViewPager(viewPager, true);

also, this shows the whole products. but how to show the pressed item first. the one that the user clicked. and then the user will be able to swap left and right browsing the whole list!?

Edit: I tried this! but now it shows a blank white page.

ArrayList<Fragment> fragments = new ArrayList<>();
    final MarketViewModel marketViewModel = new ViewModelProvider(this).get(MarketViewModel.class);
    marketViewModel.getProductInfo("parentID");
    marketViewModel.getProductInfo("parentID").observe(this, products -> {
        for (int i = 0; i < products.size(); i++) {
            Product product = products.get(i);
            ProductInfoFragment fragment = ProductInfoFragment.getInstance(product);
            fragments.add(fragment);
        }
    });
    ProductPagerAdapter adapter = new ProductPagerAdapter(getSupportFragmentManager(), 0, fragments);
    viewPager.setAdapter(adapter);
    tabLayout.setupWithViewPager(viewPager, true);
  • When you use normal data with no LiveData in place, can ViewPager display fragments normally? – Zain Apr 19 '20 at 22:22
  • Yes. I tested it and it works. I tried his example and it worked so perfectly –  Apr 19 '20 at 22:40

1 Answers1

0

Please try to build the ViewPager adapter after your LiveData submits new data, as it seems that the ViewPager is initialized with a free-of-data adapter, where its code runs before LiveData got returned.

So you would try:

ArrayList<Fragment> fragments = new ArrayList<>();
    final MarketViewModel marketViewModel = new ViewModelProvider(this).get(MarketViewModel.class);
    marketViewModel.getProductInfo("parentID");
    marketViewModel.getProductInfo("parentID").observe(this, products -> {
        for (int i = 0; i < products.size(); i++) {
            Product product = products.get(i);
            ProductInfoFragment fragment = ProductInfoFragment.getInstance(product);
            fragments.add(fragment);
        }

        ProductPagerAdapter adapter = new ProductPagerAdapter(getSupportFragmentManager(), 0, fragments);
        viewPager.setAdapter(adapter);
        tabLayout.setupWithViewPager(viewPager, true);

    });

Edit: I fixed the code but the issue persists. it shows blank while page looks like it got stuck into an infinite loop! It's so abnormal to me.

Now I will be trying to just update the ViewPager fragments within the LiveData Observer without rebuilding the adapter.

So, We'll keep the original code as-is, make the adapter as a class field, and call mAdapter.notifyDataSetChanged() for new data returned by LiveData.

ProductPagerAdapter mAdapter;

ArrayList<Fragment> fragments = new ArrayList<>();
    mAdapter = new ProductPagerAdapter(getSupportFragmentManager(), 0, fragments);
    viewPager.setAdapter(mAdapter);
    tabLayout.setupWithViewPager(viewPager, true);

    final MarketViewModel marketViewModel = new ViewModelProvider(this).get(MarketViewModel.class);
    marketViewModel.getProductInfo("parentID");
    marketViewModel.getProductInfo("parentID").observe(this, products -> {
        for (int i = 0; i < products.size(); i++) {
            Product product = products.get(i);
            ProductInfoFragment fragment = ProductInfoFragment.getInstance(product);
            fragments.add(fragment);
        }

         mAdapter.notifyDataSetChanged();  // <<<<<< here updating adapter fragemnts

    });

Also, this answer may help you to update your adapter fragments correctly.

Zain
  • 37,492
  • 7
  • 60
  • 84
  • thank you for replying. I fixed the code but the issue persists. it shows blank while page looks like it got stuck into an infinite loop! It's so abnormal to me. like the logic to me at least makes sense. –  Apr 19 '20 at 22:54
  • @Alaa thank you for your comment, please check updated answer in `Edit` section – Zain Apr 19 '20 at 23:08
  • In the edited version. you have declared a new adapter without initializing it. why! cuz i tried it now and it threw Null exception. but why would I use 2 discrete adapters! –  Apr 20 '20 at 00:03
  • @Alaa sorry just use mAdapter in all, I missed that; I updated the answer – Zain Apr 20 '20 at 00:06
  • thank you for the time u r spending with me. I know its tedious for u but it's just new materials for me. I can't declare it like this without initializing it since I'm inside an interface. if I initialize it to null it throws an exception. and I cant use the constructor. what should I do! –  Apr 20 '20 at 00:12
  • @Alaa excuse me what do you need to intialize inside the interface? – Zain Apr 20 '20 at 00:14
  • mAdapter.notifyDataSetChanged(); here it gives an error saying mAdapter might have not been initialized. I tried to set it to null but threw exception. –  Apr 20 '20 at 00:17
  • @Alaa just move your code above the liveData listener .. I updated the answer for that – Zain Apr 20 '20 at 00:20
  • after debugging. at the end of the method execution, the fragment array size is 0 and the adapter is null. when it reaches this line mAdapter.notifyDataSetChanged(); everything is empty. is it that hard to implement or I'm just so not smart of it! –  Apr 20 '20 at 00:28
  • 1
    omg, you helped me so much by just replying. it's so frustrating spacially when its uni final year project. but I will never give up. thank you –  Apr 20 '20 at 00:37
  • it worked. it was a stupid mistake by me elsewhere and now it works. the last thing wanna ask how to show the pressed item first like how to get the item position that's pressed. –  Apr 20 '20 at 01:28
  • Your code was correct. I just had a method that filters the products by parentID. but dumb me I was providing the wrong argument. I feel so ashamed for wasting ur time but triumphed for making it work at least. not fully but still –  Apr 20 '20 at 01:40
  • @Alaa no worries for time waste; the important thing that you get it solved. I didn't get your last question can you explain it more "how to get the item position that's pressed ?" – Zain Apr 20 '20 at 01:42
  • I have a category that contains 100 products, 3 subcategories. each 30 item corresponds to one subcategory. so let's say the user chose one subcategory. now the 30 products are presented in short view mode. once a product is pressed the new activity will launch with more detail about this product. here where the viewpager will be functioning. now I got it to work on how to show all the 30 items. but what if the user pressed item number 13. I must show this item first. if the user swaps left he gets item number 12 if right the item number 14. etc. how to do this is my next job –  Apr 20 '20 at 01:48
  • 1
    @Alaa so when the user press item number 13, you need your ViewPager go to page number 13 I guess; so you can do that by `mViewPager.setCurrentItem(13);` .. or I guess it could be 12 as it's 0-based – Zain Apr 20 '20 at 01:58
  • You saved my life I swear. thank you from the bottom of my heart –  Apr 20 '20 at 01:59
  • @Alaa welcome man wish you get the highest grade in your project :) – Zain Apr 20 '20 at 02:00