Sudhir Singh Khanger
Sudhir Singh Khanger

Reputation: 1628

Unable to restore RecyclerView's position/state

Whenever I move from DetailsActivity to MainActivity the RecyclerView is reset and list is always shown from the top position.

Full source code can be seen here. The code is still largely a work in progress.

MainActivityFragment is as follows.

public class MainActivityFragment extends Fragment {

    private ArrayList<Movie> mMovieArrayList = new ArrayList<Movie>();
    private static final String PAGE = "1";
    private RecyclerView mRecyclerView;

    private SharedPreferences mSettings;
    private SharedPreferences.Editor mEditor;

    private static final String LOG = MainActivityFragment.class.getSimpleName();

    public MainActivityFragment() {
    }

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

        View rootView = inflater.inflate(R.layout.fragment_movie_list, container, false);

        // Set column size to 2 for default and portrait
        // and 3 for landscape orientations
        int column = Integer.parseInt(getString(R.string.grid_portrait));
        if (getResources().getConfiguration().orientation == 1) {
            column = Integer.parseInt(getString(R.string.grid_portrait));
        } else if (getResources().getConfiguration().orientation == 2) {
            column = Integer.parseInt(getString(R.string.grid_landscape));
        }

        if (getActivity().findViewById(R.id.movie_detail_container) != null) {
            column = Integer.parseInt("2");
        }

        mSettings = PreferenceManager.getDefaultSharedPreferences(getActivity());
        mEditor = mSettings.edit();
        mEditor.apply();

        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), column));

        mRecyclerView.setAdapter(new MovieAdapter(getActivity(), mMovieArrayList));
        return rootView;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onStart() {
        super.onStart();
        updateMovieList();
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_main_fragment, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.popularity:
                mEditor.putString(getResources().getString(R.string.perf_sort),
                        getResources().getString(R.string.url_popularity));
                mEditor.apply();
                updateMovieList();
                item.setChecked(true);
                Log.d(LOG, "onOptionsItemSelected: popularity");
                return true;
            case R.id.rating:
                mEditor.putString(getResources().getString(R.string.perf_sort),
                        getResources().getString(R.string.url_top_rated));
                mEditor.apply();
                updateMovieList();
                item.setChecked(true);
                Log.d(LOG, "onOptionsItemSelected: rating");
                return true;
            case R.id.favorite:
                mEditor.putString(getResources().getString(R.string.perf_sort),
                        getResources().getString(R.string.url_favorite));
                mEditor.apply();
                updateMovieList();
                item.setChecked(true);
                Log.d(LOG, "onOptionsItemSelected: favorite");
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);

        String sortBy = mSettings.getString(getResources().getString(R.string.perf_sort),
                getResources().getString(R.string.url_popularity));

        if (sortBy.equals(getResources().getString(R.string.url_popularity))) {
            menu.findItem(R.id.popularity).setChecked(true);
        } else if (sortBy.equals(getResources().getString(R.string.url_top_rated))) {
            menu.findItem(R.id.rating).setChecked(true);
        } else if (sortBy.equals(getResources().getString(R.string.url_favorite))) {
            menu.findItem(R.id.favorite).setChecked(true);
        }
    }

    private void updateMovieList() {
        mMovieArrayList = new ArrayList<>();
        String sortBy = mSettings.getString(getResources().getString(R.string.perf_sort),
                getResources().getString(R.string.url_popularity));

        if (sortBy.equals(getResources().getString(R.string.url_popularity)) ||
                sortBy.equals(getResources().getString(R.string.url_top_rated))) {

            try {
                mMovieArrayList =
                        new FetchMoviesTask().execute(sortBy, PAGE).get();
            } catch (ExecutionException | InterruptedException ei) {
                ei.printStackTrace();
            }
        } else if (sortBy.equals(getResources().getString(R.string.url_favorite))) {
            ContentResolver resolver = getActivity().getContentResolver();
            Cursor cursor =
                    resolver.query(MovieContract.MovieEntry.CONTENT_URI,
                            null,
                            null,
                            null,
                            null);

            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    do {
                        String title = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.TITLE));
                        String movie_id = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.MOVIE_ID));
                        String poster = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.POSTER));
                        String backdrop = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.BACKDROP));
                        String overview = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.OVERVIEW));
                        String vote_average = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.VOTE_AVERAGE));
                        String release_date = cursor.getString(cursor.getColumnIndex(MovieContract.MovieEntry.DATE));

                        Movie movie = new Movie(title, release_date, poster,
                                vote_average, overview, backdrop, movie_id);
                        mMovieArrayList.add(movie);
                    } while (cursor.moveToNext());
                }
            }

            if (cursor != null)
                cursor.close();
        }

        mRecyclerView.setAdapter(new MovieAdapter(getActivity(), mMovieArrayList));
        mRecyclerView.getAdapter().notifyDataSetChanged();
    }
}

MainActivity is as follows.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

//        if (id == android.R.id.home) {
//            onBackPressed();
//            return true;
//        }

        return super.onOptionsItemSelected(item);
    }
}

I have tried setting saving up RecyclerView's state like shown in this post.

I have also tried saving the mArrayList in onSaveInstanceState and restoring it in onActivityCreated or onViewCreated like in this post.

Both of these have not worked for me. As soon as I return back from the DetailsActivity to MainActivity the position is gone.

Thanks.

Upvotes: 1

Views: 278

Answers (2)

daxgirl
daxgirl

Reputation: 772

  1. You're calling a method to update movies list in onStart callback of fragment life cycle. Which means when your main activity is shown back, you're resetting your list. You shouldn't.
  2. You set a new instance of adapter at the end of update list method. That redraws the entire list. You should rethink your life cycles. Call update movie list only in onCreate or onCreateView and always check if adapter opject is null and only then use setAdapter method on recycler view. If adapter is not null, just call notifyDataSetChanged or whatever is needed to update your items.

Upvotes: 1

Cilvet
Cilvet

Reputation: 470

Maybe this could help. Eventhough it will scroll all the way to the selected item each time.

Upvotes: 0

Related Questions