0

I want to know how to switch to the current item of viewpager when a recyclerview item clicked

when clicking on a recyclerview item it will return the position of the clicked item easily. a toast message confirms this.

but when I use mViewPager.setCurrentItem(position); it returns null , I can confirm that viewpager has been initialized successfully because it is working well in onCreate of my activity.

here is the adapter of the recyclerview



    // ViewHolder adapter for RecyclerView
        public class PlanetViewHolder
                extends RecyclerView.ViewHolder
                implements View.OnClickListener {
            public PlanetViewHolder(View v) {
                super(v);
                v.setOnClickListener(this);
            }
    
            @Override
            public void onClick(View v) {
                int position = getPosition();
                mViewPager.setCurrentItem(position);    
                Toast.makeText(getContext(), "You have clicked " + ((TextView) v).getText(), Toast.LENGTH_SHORT).show();
    
    
            }
        }

here is the onCreate

public class TvShowEpisodeDetails extends MizActivity {

    private static final String SHOW_ID = "showId";

    private ArrayList<TvShowEpisode> mEpisodes = new ArrayList<TvShowEpisode>();
    private int mSeason, mEpisode;
    private String mShowId, mShowTitle;
    private ViewPager mViewPager;
    private DbAdapterTvShowEpisodes mDatabaseHelper;
    private Bus mBus;

    @Override
    protected int getLayoutResource() {
        return R.layout.viewpager_with_toolbar_overlay;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        mBus = MizuuApplication.getBus();
        super.onCreate(savedInstanceState);

        // Set theme
        setTheme(R.style.Mizuu_Theme_NoBackground);

        ViewUtils.setupWindowFlagsForStatusbarOverlay(getWindow(), true);

        ViewUtils.setProperToolbarSize(this, mToolbar);

        mShowId = getIntent().getExtras().getString(SHOW_ID);
        mSeason = getIntent().getExtras().getInt("season");
        mEpisode = getIntent().getExtras().getInt("episode");

        mDatabaseHelper = MizuuApplication.getTvEpisodeDbAdapter();

        Cursor cursor = mDatabaseHelper.getEpisodes(mShowId);
        try {
            while (cursor.moveToNext()) {
                mEpisodes.add(new TvShowEpisode(this, mShowId,
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_TITLE)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_PLOT)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_SEASON)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_AIRDATE)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_DIRECTOR)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_WRITER)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_GUESTSTARS)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_EPISODE_RATING)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_HAS_WATCHED)),
                        cursor.getString(cursor.getColumnIndex(DbAdapterTvShowEpisodes.KEY_FAVOURITE))
                        ));
            }
        } catch (Exception e) {
        } finally {
            cursor.close();
        }

        mShowTitle = MizuuApplication.getTvDbAdapter().getShowTitle(mShowId);
        setTitle(mShowTitle);

        mViewPager = (ViewPager) findViewById(R.id.awesomepager);
        mViewPager.setAdapter(new TvShowEpisodeDetailsAdapter(getSupportFragmentManager()));
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                ViewUtils.updateToolbarBackground(TvShowEpisodeDetails.this, mToolbar, 0, mEpisodes.get(position).getTitle(), Color.TRANSPARENT);
            }
        });

        if (savedInstanceState != null) {
            mViewPager.setCurrentItem(savedInstanceState.getInt("tab", 0));
        } else {
            for (int i = 0; i < mEpisodes.size(); i++) {
                if (mEpisodes.get(i).getSeason().equals(MizLib.addIndexZero(mSeason)) && mEpisodes.get(i).getEpisode().equals(MizLib.addIndexZero(mEpisode))) {
                    mViewPager.setCurrentItem(i);
                    break;
                }
            }
        }
    }


    // ViewHolder adapter for RecyclerView
    public class PlanetViewHolder
            extends RecyclerView.ViewHolder
            implements View.OnClickListener {
        public PlanetViewHolder(View v) {
            super(v);
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            int position = getPosition();
            mViewPager.setCurrentItem(position);

            //mViewPager.setAdapter(new TvShowEpisodeDetailsAdapter(getSupportFragmentManager()));
            //mViewPager.setCurrentItem(position);
            //Toast.makeText(getContext(), "You have clicked " + ((TextView) v).getText(), Toast.LENGTH_SHORT).show();


        }
    }
rest of the code
}

1 Answers1

0

Based on your stacktraces, I can conclude that the way you handle UI elements are in the wrong order, meaning lifecycle is ignored.

You should NOT invoke UI elements in your activity from your viewHolder, as viewHolders are "part" of Recyercycleview which is not aware of the activity lifecycle.

A common pattern to invoke UI elements in your activity from your viewHolder is:

            Listener
Activity <-----------> RecyclerView_Adapter

Well, since you have a listener already, your have a good start.

Just move your mViewPager.setCurrentItem(position); from viewHolder to inside the overriden onClick Method in Activity through the listener you have.

Let me know if you have more questions, you are almost there!

EDIT

If your viewpager is in a fragment, then you should add mViewPager.setCurrentItem(position); to the overriden onClick Method in fragment. Simply means that you should invoke mViewPager.setCurrentItem(position); directly from your fragment and use the Adapter Listener just to get the correct time to invoke mViewPager.setCurrentItem(position);.

What is an Adapter Listener in Android?

minchaej
  • 1,294
  • 1
  • 7
  • 14
  • I really appreciate it if you could help me out –  Jun 15 '21 at 15:23
  • the RecyclerView is inside the fragment class of this activity –  Jun 15 '21 at 15:25
  • Sure i have made an edit. It would solve it now – minchaej Jun 15 '21 at 15:31
  • I'm sorry but I'm still confused , but what I'm saying is `RecyclerView` is inside the fragment not the `viewpager` , the `viewpager` is in the activity that I shown above I mean `MizActivity` –  Jun 15 '21 at 15:37
  • Here is the code form my **[fragment](https://pastebin.com/hq9p6MEL)** –  Jun 15 '21 at 15:38
  • viewpager is in the activity that I shown above I mean `TvShowEpisodeDetails` –  Jun 15 '21 at 15:44
  • here is the **[viewpager adapter](https://pastebin.com/5VRdRCQC)** which is inside `TvShowEpisodeDetails` –  Jun 15 '21 at 15:46
  • the `mViewPager.setCurrentItem(position);` where do you mean I should move it ?, because it is already inside the `onClick` Method –  Jun 15 '21 at 15:59
  • Hi cyberpunk, now that I saw the source code I have a better understanding. It seems like you lack the implementation of Listener Pattern in Android. You need to apply this in order to achieve your desired behavior. Please checkout out this article and apply it in your app. https://medium.com/android-gate/recyclerview-item-click-listener-the-right-way-daecc838fbb9 – minchaej Jun 15 '21 at 16:12
  • Ok I will do it right away , please help me out if I'm stuck –  Jun 15 '21 at 16:15
  • Sure, feel free to ask me :) – minchaej Jun 15 '21 at 16:22
  • I'm trying to apply it to my code , but the problem is , the example code uses kotlin , which I know nothing about , I don't know about this `fun` thing , please forgive me for that –  Jun 15 '21 at 16:31
  • Sure, if you are not comfortable with kotlin, there is a java version too: https://stackoverflow.com/questions/49969278/recyclerview-item-click-listener-the-right-way – minchaej Jun 15 '21 at 17:03
  • Thank you , I will use that –  Jun 15 '21 at 17:11
  • I recreated the adapter class from scratch **[here it is](https://pastebin.com/5Kh1veTp)** now I some help need to apply `mViewPager.setCurrentItem(position); ` because viewpager is not initialized inside the fragment –  Jun 15 '21 at 20:46
  • here is a **[video of my app](https://youtu.be/VkMa031JkRc)** , when I click an item from the scrollbar it force closes the view –  Jun 15 '21 at 23:54
  • When I run it, I get **[NullPointerException](https://pastebin.com/Kz8xMv5b)** at `listener.onItemClick(item);` –  Jun 16 '21 at 10:17
  • `listener` is null but `item` returns values here is breakpoint at **[listener.onItemClick(item)](https://imgur.com/G50KJVT)** –  Jun 16 '21 at 10:23
  • I appreciate some help, I'm really stuck –  Jun 16 '21 at 11:47
  • My problem is not solved but I will accept your answer , thank you for your help. –  Jun 16 '21 at 16:43
  • Sorry @cyberpunk I was a little busy with something else. It seems like you have done an excellent job with implementing Adapter Class. However, you are encountering NullPointerException because your adapter is declared as `Static` Member. Adapters should never be static as it could cause a alot of exceptions. Thanks – minchaej Jun 16 '21 at 19:47
  • line 10 of `PlanetAdapter ` --> `static OnItemClickListener listener;` – minchaej Jun 16 '21 at 19:48
  • Thank you so much , no problem, I removed the static but I get `Non-static field can not be declared from a static contest` –  Jun 16 '21 at 20:03
  • I just realized that PlanetAdapter class is declared as static; `public static class PlanetAdapter`. You should NEVER declare an adapter class as static. In addition, using static is a really bad pattern in Android Development, which causes all kinds of lifecycle error because static classes are not aware of Android's lifecycle. Please remove all static properties in adapter. Thanks – minchaej Jun 16 '21 at 20:13
  • Can you please help me with implementing `mViewPager.setCurrentItem(position);` –  Jun 16 '21 at 20:19
  • I created a new jave file for **[PlanetAdapter](https://pastebin.com/BBYhVpsp)** named `PlanetAdapter.java` in order to get rid of the all static declarations, but I still get null from `listener` and **[NullPointerException](https://pastebin.com/v3H8qY7N)** here is the **[fragment](https://pastebin.com/qEEHWcKL)** –  Jun 16 '21 at 22:22
  • I also made `OnItemClickListener listener;` public on both ends I still get **[NullPointerException](https://pastebin.com/yGpVXhzX)** –  Jun 16 '21 at 22:30
  • I got rid of the NullPointerException from the `listener` now `listener` returnes value , now all I need is implement `mViewPager.setCurrentItem(position);` here is [TvShowEpisodeDetailsFragment](https://pastebin.com/VvGgcTit) , here is [PlanetAdapter](https://pastebin.com/aRwdeY4J) –  Jun 17 '21 at 20:04
  • Hey @cyberpunk, you did a great job on eliminating Static elements and solving Nullpointer on `listener`. I just saw your code and things look very nice now. On line 37 of TvShowEpisodeDetailsFragment, I already see that you have correctly placed `mViewPager.setCurrentItem(position);`. Was this source code changed after you have commented? – minchaej Jun 18 '21 at 08:51
  • Yes , I did some editing after that , I created an interface inside [TvShowEpisodeDetailsFragment](https://pastebin.com/1TAnzjN0) to transfer **onClick** to [TvShowEpisodeDetails](https://pastebin.com/gdQYzGjc) , here is [PlanetAdapter](https://pastebin.com/jEpR5xYc) and I got exactly what I needed , thank you for putting me on the right path, I'm forever grateful. –  Jun 18 '21 at 09:02
  • "I created an interface inside TvShowEpisodeDetailsFragment to transfer onClick to TvShowEpisodeDetails" <-- This was what I needed! Nice! Yes, `interface` will be your friend when dealing with adapters. I am genuinely glad that you were able to do it! Thanks. – minchaej Jun 18 '21 at 09:19
  • thank you so much , you are the who put me on the right path. –  Jun 18 '21 at 09:22