简体   繁体   English

如何正确恢复旋转状态?

[英]How to properly restore view state on rotation?

I know this question relates to this question RecyclerView store / restore state between activities but it is specific to my own problem, maybe you can help. 我知道这个问题与此问题相关, RecyclerView在活动之间存储/恢复状态,但这是我自己的问题,也许您可​​以提供帮助。 I won't post all the code as there is a LOT of it. 我不会发布所有代码,因为有很多代码。

In the MainActivity below I want follow what what is suggested in that answer, the only difference is that I use SharePreference to distinguish between what view was last on the screen. 在下面的MainActivity中,我要遵循该答案中的建议,唯一的区别是,我使用SharePreference来区分屏幕上的最后一个视图。 For some reason it still loads the items for layoutManager on rotation. 由于某些原因,它仍在旋转时为layoutManager加载项目。 Not only this, but it does not even save the state of that view, it just resets. 不仅如此,它甚至不保存该视图的状态,它只是重置。 I posted all the code from this Activity in the hopes that someone can spot where I went wrong. 我发布了本次Activity所有代码,希望有人能发现我哪里出了问题。 I can also post the github link if needed. 如果需要,我还可以发布github链接。 Whole app can not be used unless you have API key described in the github. 除非您具有github中描述的API密钥,否则无法使用整个应用程序。 Please let me know if you need the AndroidManifest or anything else. 如果您需要AndroidManifest或其他任何东西,请告诉我。

public class MainActivity extends AppCompatActivity implements PosterAdapter.PosterItemClickHandler, FavoritesAdapter.FavoritesClickHandler {

private PosterAdapter posterAdapter;
private FavoritesAdapter favoritesAdapter;
private GridLayoutManager layoutManager;
private GridLayoutManager layoutManager1;
private MovieDataBase mDb;
private SharedPreferences prefs;
private SharedPreferences.Editor editor;
private final String FavoriteViewState = "favorites-view-state";
private boolean VIEWSTATE1;
private Parcelable favListState;
private final String FavListKey = "favorites-key";
private Bundle mBundleRecyclerViewState;



@BindView(R.id.rv_posters)RecyclerView mRecyclerViews;
@BindView(R.id.tv_error_message1) TextView mErrorMessage1;
@BindView(R.id.tv_error_message2) TextView mErrorMessage2;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ButterKnife.bind(this);
    mDb = MovieDataBase.getInstance(getApplicationContext());

    setRecyclerViews();
    updateUI(popularSortLink);
    loadFavoritesData();

    prefs = PreferenceManager.getDefaultSharedPreferences(this);

    if(savedInstanceState != null){
        boolean favoritesState = prefs.getBoolean(FavoriteViewState, VIEWSTATE1);
        if(favoritesState) {
            favListState = savedInstanceState.getParcelableArrayList(FavListKey);
            //List<MovieEntry> movies = new ArrayList<>(favListState);
            if(favListState != null) {
                favoritesAdapter = new FavoritesAdapter(favListState, MainActivity.this);
                //favoritesAdapter.setFavorites(favListState);
                mRecyclerViews.setLayoutManager(layoutManager1);
                mRecyclerViews.setHasFixedSize(false);
                mRecyclerViews.setAdapter(favoritesAdapter);
            }
        }
    }
}


// This method sets the recycler views for the main screen
public void setRecyclerViews(){
    // Create the grid layout and apply it to the poster recycler view
    layoutManager = new GridLayoutManager(this,3);
    layoutManager1 = new GridLayoutManager(this,1);
    mRecyclerViews.setLayoutManager(layoutManager);
    mRecyclerViews.setHasFixedSize(true);

}

// This method updates the UI based on whether there is a network connection or not.
public void updateUI(String movieLink){
    if(!isOnline()){
        mErrorMessage1.setVisibility(View.VISIBLE);
        mRecyclerViews.setVisibility(View.INVISIBLE);
    }else{
        mErrorMessage1.setVisibility(View.INVISIBLE);
        mRecyclerViews.setVisibility(View.VISIBLE);
        startApp(movieLink);
    }
}

//Information sourced from https://developer.android.com/training/volley/requestqueue
//09/11/18
// This method makes a network request using Androids Volley mechanisms to retrieve the json data
private void startApp(String movieLink){
    RequestQueue mRequestQueue;
    // Instantiate the cache
    Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap
    // Set up the network to use HttpURLConnection as the HTTP client.
    Network network = new BasicNetwork(new HurlStack());
    // Instantiate the RequestQueue with the cache and network.
    mRequestQueue = new RequestQueue(cache, network);
    // Start the queue
    mRequestQueue.start();

    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
            (Request.Method.GET, movieLink, null, new Response.Listener<JSONObject>() {

                @Override
                public void onResponse(JSONObject response) {

                    setRecyclerViews();
                    mErrorMessage2.setVisibility(View.INVISIBLE);
                    mRecyclerViews.setVisibility(View.VISIBLE);
                    VIEWSTATE1 = false;
                    editor = prefs.edit();
                    editor.putBoolean(FavoriteViewState, VIEWSTATE1);
                    editor.apply();

                    //Parse the JSON string and store in a list of Movie objects
                    List<MovieDetails> movieDetailsList = JsonUtility.parseMovieDetailsJson(response);

                    // display the data
                    loadMovieData(movieDetailsList);
                }
            }, new Response.ErrorListener() {

                @Override
                public void onErrorResponse(VolleyError error) {
                    // TODO: Handle error
                    Log.i("TAG", error.toString());
                    mErrorMessage2.setVisibility(View.VISIBLE);
                    mRecyclerViews.setVisibility(View.INVISIBLE);
                    VIEWSTATE1 = false;
                    editor = prefs.edit();
                    editor.putBoolean(FavoriteViewState, VIEWSTATE1);
                    editor.apply();
                }
            });
    mRequestQueue.add(jsonObjectRequest);
}

public void loadMovieData(List movieDetailsList){
    //Create the adapter using the MovieDetails lists and apply the adapter to the recycler view
    posterAdapter = new PosterAdapter(movieDetailsList, this);
    mRecyclerViews.setAdapter(posterAdapter);
}

// This method views changes in the favorites database and updates it's cooresponding recycler view
public void loadFavoritesData(){
    MainViewModel viewModel = ViewModelProviders.of(this).get(MainViewModel.class);
    viewModel.getMovies().observe(this, new Observer<List<MovieEntry>>() {
        @Override
        public void onChanged(@Nullable List<MovieEntry> movieEntries) {
            Log.d("TAG", "UPDATE FROM THE DATABASE using livedata in viewmodel");
            favoritesAdapter = new FavoritesAdapter(movieEntries, MainActivity.this);
        }
    });

}


//This method updates the main view to show the favorites list
public void showFavsList(){


    mRecyclerViews.setLayoutManager(layoutManager1);
    mRecyclerViews.setHasFixedSize(false);
    mRecyclerViews.setAdapter(favoritesAdapter);
    mErrorMessage1.setVisibility(View.INVISIBLE);
    VIEWSTATE1 = true;
    editor = prefs.edit();
    editor.putBoolean(FavoriteViewState, VIEWSTATE1);
    editor.apply();
}

@Override //This method opens the next activity and loads data based on the index passed through from the adapter onClick method
public void onPosterItemClick(MovieDetails movieDetails) {

    String parcelData = MainActivity.this.getString(R.string.parcel_data);
    Intent intent = new Intent(this, DetailActivity.class);
    intent.putExtra(parcelData, movieDetails);
    startActivity(intent);
} 

@Override //Override this method to inflate the menu resource
public boolean onCreateOptionsMenu(Menu menu) {

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.sort_by, menu);
    return true;
}

@Override //Handle clicks on certain menu items. In this case it handles the sorting methods.
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if(id == R.id.popular_sort){
        updateUI(popularSortLink);
        return true;
    }else if(id == R.id.rating_sort){
        updateUI(topRatingSortLink);
        return true;
    }else if(id == R.id.favorites_sort){
        // display the favorites list
        showFavsList();
        return true;
    }
    return super.onOptionsItemSelected(item);
}


@Override   
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    favoritesState = prefs.getBoolean(FavoriteViewState, VIEWSTATE1);

    //Log.d("TEST", String.valueOf(favoritesState));
    if(favoritesState){
        outState.putParcelableArrayList(FavListKey,favListState);
    }
}
}
  1. Use onSaveInstanceState(Bundle bundle) instead of onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) . 使用onSaveInstanceState(Bundle bundle)代替onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)
  2. Don't override onRestoreInstanceState(Bundle savedInstanceState) , you're getting Bundle object in onCreate() . 不要重写onRestoreInstanceState(Bundle savedInstanceState) ,您将在onCreate()获得Bundle对象。 Restore your state in there. 在那恢复您的状态。
  3. Instead of using SharedPreferences to save state in key FavoriteViewState use onSaveInstanceState() and onCreate() . 代替使用SharedPreferences将状态保存在FavoriteViewState键中,请使用onSaveInstanceState()onCreate() SharedPreferences is overkill in here. 在这里, SharedPreferences是多余的。
  4. In setRecyclerViews() you're always setting layoutManger as your manager. setRecyclerViews()您始终将layoutManger设置为您的经理。 It may be a problem, it's hard to say without debuging your code. 这可能是一个问题,如果不调试代码就很难说。

EDIT 05.01.2019: 编辑05.01.2019:

layoutManager.onSaveInstanceState() which returns Parcelable object dont work like that. 返回Parcelable对象的layoutManager.onSaveInstanceState()那样工作。 You're not supposed to call it in your class, forget about it, it is called internally. 您不应该在班级中调用它,而忽略它,它是在内部调用的。 In order to restore your view properly, in onSaveInstanceState() you need to save your data list which will be restored later in onCreate() . 为了正确还原视图,您需要在onSaveInstanceState()中保存数据列表,该列表稍后将在onCreate()还原。 You can also save there your last clicked position and in your case, information about which layout manager should be set after view will be recreate. 您还可以将最后单击的位置保存在那里,在这种情况下,将在重新创建视图后重新设置应该设置哪个布局管理器的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM