Search code examples
javaandroidandroid-recyclervieworientationonsaveinstancestate

How can I keep my RecyclerView after android rotation?


When I rotate my device, my activity instance is destroyed which starts a new onCreate. I can't figure out how to repopulate my RecyclerView after screen orientation. I have tried some solutions involing AndroidManifest: android:configChanges="keyboardHidden|orientation" and also with onSaveInstanceState, but could not get it to work. I have addedonSaveInstanceStateandonRestoreInstanceState` base code to my question, which does not do anything at the moment.

Thanks

MainActivity.java

public class MainActivity extends AppCompatActivity implements RepositoryAdapter.OnItemClickListener {

    private static final String LOG_TAG = "MainActivity";

    @BindView(R.id.fab_search_github_user)
    FloatingActionButton fabSearchGitHubUser;

    @BindView(R.id.et_search_user)
    EditText etSearchUser;

    @BindView(R.id.btn_search_user)
    Button btnSearchUser;

    @BindView(R.id.github_user)
    TextView tvOwner;

    @BindView(R.id.github_repository_recyclerview)
    RecyclerView mRecyclerView;

    private RepositoryAdapter mAdapter;

    private Api mApi;

    private Owner mOwner;

    boolean isSearchToggled = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ButterKnife.bind(this);

        mApi = ApiUtils.getApi();

        // RecyclerView
        RecyclerView.LayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
        mRecyclerView.setLayoutManager(linearLayoutManager);
        mRecyclerView.setHasFixedSize(true);

        // Floating action button to toggle user search field.
        FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab_search_github_user);
        floatingActionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toggleSearch();
            }
        });
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    }

    @OnClick(R.id.btn_search_user)
    public void onSearchBtnClicked(View view) {
        if (!TextUtils.isEmpty(etSearchUser.getText())) {
            String searchedUser = etSearchUser.getText().toString();

            // Search will be done offline when no internet, otherwise online.
            if (!isNetworkAvailable()) {
                Toast.makeText(this, "No internet, searching offline", Toast.LENGTH_SHORT).show();
                mOwner = Owner.getByUsername(searchedUser);
                if (mOwner != null) {
                    searchByUsername(searchedUser);
                    tvOwner.setText(searchedUser);
                } else {
                    if (mAdapter != null) {
                        mAdapter.clearRecyclerView();
                    }
                    tvOwner.setText(getString(R.string.user_not_found, searchedUser));
                }
            } else {
                loadRepository(searchedUser);
                tvOwner.setText(searchedUser);
                Toast.makeText(this, "Searching online", Toast.LENGTH_SHORT).show();
            }
        } else {
            Log.i(LOG_TAG, "Search field is empty");
        }

        if (view != null) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }

        toggleSearch();
    }

    /**
     * Search local user by username.
     *
     * @param username The local user that is searched for.
     */
    public void searchByUsername(String username) {
        mAdapter = new RepositoryAdapter(Repository.getList(username), MainActivity.this);
        mRecyclerView.setAdapter(mAdapter);
    }

    /**
     * Search online on GitHub to retrieve all user repositories.
     *
     * @param username The GitHub user that is searched for.
     */
    public void loadRepository(String username) {
        mApi.listRepository(username).enqueue(new Callback<List<Repository>>() {
            @Override
            public void onResponse(Call<List<Repository>> call, Response<List<Repository>> response) {
                mAdapter = new RepositoryAdapter(response.body(), MainActivity.this);
                mRecyclerView.setAdapter(mAdapter);
            }

            @Override
            public void onFailure(Call<List<Repository>> call, Throwable t) {
                Log.e("MainActivity", "error loading from API");
            }
        });
    }

    @Override
    public void onItemClick(Repository repository) {
        if (isNetworkAvailable()) {
            mOwner = Owner.getByUsername(repository.owner.getLogin());
            Repository mRepository = Repository.getByRepositoryName(repository.getName());

            if (mOwner != null) {
                if (mRepository != null) {
                    // Repository is already in Database.
                } else {
                    // Selected repository is added to Database
                    mRepository = new Repository(mOwner);
                    mRepository.setName(repository.getName());
                    mRepository.setLogin(repository.owner.getLogin());
                    mRepository.setDescription(repository.getDescription());
                    mRepository.setStargazersCount(repository.getStargazersCount());
                    mRepository.setForksCount(repository.getForksCount());
                    mRepository.save();
                }
            } else {
                // selected repository and its owner are added to Database
                mOwner = new Owner();
                mOwner.setLogin(repository.owner.getLogin());
                mOwner.setAvatarUrl(repository.owner.getAvatarUrl());
                mOwner.setReposUrl(repository.owner.getReposUrl());
                mOwner.save();

                mRepository = new Repository(mOwner);
                mRepository.setName(repository.getName());
                mRepository.setLogin(repository.owner.getLogin());
                mRepository.setDescription(repository.getDescription());
                mRepository.setStargazersCount(repository.getStargazersCount());
                mRepository.setForksCount(repository.getForksCount());
                mRepository.save();
            }
        }

        // Send intent with repository name to repository detail activity.
        Intent intent = new Intent(MainActivity.this, RepositoryDetailActivity.class);
        intent.putExtra(INTENT_KEY_REPOSITORY, repository.getName());
        startActivity(intent);
    }

    /**
     * Toggle search field according to its state.
     */
    private void toggleSearch() {
        if (!isSearchToggled) {
            etSearchUser.setVisibility(View.VISIBLE);
            btnSearchUser.setVisibility(View.VISIBLE);
            isSearchToggled = true;
        } else {
            etSearchUser.setVisibility(View.GONE);
            btnSearchUser.setVisibility(View.GONE);
            isSearchToggled = false;
        }
    }

    /**
     * Checks if network is available on the device.
     *
     * @return Return when networkInfo is not null and networkInfo is connected.
     */
    private boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        return networkInfo != null && networkInfo.isConnected();
    }
}

Solution

    1. configChanges also should include screenSize if you want turn off recreating activity class. So correct version:

      android:configChanges="keyboardHidden|orientation|screenSize"

    2. In order to save recycler view content without disabling recreating you have to store content in some place which is not bound to activity lifecycle or pass it to bundle in onSaveInstanceState and get it later in onRestoreInstanceState or in onCreate. Please, take a look at https://developer.android.com/guide/components/activities/activity-lifecycle.html