【问题标题】:How to Save State Data inside recyclerview when screen rotated屏幕旋转时如何在recyclerview中保存状态数据
【发布时间】:2019-08-11 04:38:12
【问题描述】:

我使用 android java 编程语言创建了一个电影应用程序,使用 API 从 TMDB 获取数据,一切都很好并且按我预期的那样工作,但问题是当屏幕旋转时数据一次又一次地重新加载,我正在关注该网站上的一些教程,但仍然无法正常工作。

我正在关注此链接:How to save an Android Activity state using save instance state?,但我无法确定要在我的案例中实施本教程

// this is my Movie Fragment
package com.ogi.layarkacamobile.fragment;


import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

import com.ogi.layarkacamobile.MainActivity;
import com.ogi.layarkacamobile.R;
import com.ogi.layarkacamobile.adapter.MoviesAdapter;
import com.ogi.layarkacamobile.api.Client;
import com.ogi.layarkacamobile.api.Service;
import com.ogi.layarkacamobile.model.movie.MovieData;
import com.ogi.layarkacamobile.model.movie.MoviesResponse;
import com.ogi.layarkacamobile.util.PaginationScrollListener;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**
 * A simple {@link Fragment} subclass.
 */
public class MoviesFragment extends Fragment {
    private static final String TAG = "MoviesFragment";

    RecyclerView rvMoviesList;
    ProgressBar pbMovies;
    MoviesAdapter moviesAdapter;
    LinearLayoutManager linearLayoutManager;

    private static final int PAGE_START = 1;
    private boolean isLoading = false;
    private boolean isLastPage = false;

    private int TOTAL_PAGES = 10;
    private int currentPage = PAGE_START;

    private Service movieService;

    public MoviesFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View layout = LayoutInflater.from(getContext()).inflate(R.layout.fragment_movies, container, false);
        rvMoviesList = layout.findViewById(R.id.rv_movies_id);
        pbMovies = layout.findViewById(R.id.pb_movies_id);
        moviesAdapter = new MoviesAdapter(getContext());

        linearLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
        rvMoviesList.setLayoutManager(linearLayoutManager);

        rvMoviesList.setItemAnimator(new DefaultItemAnimator());
        rvMoviesList.setAdapter(moviesAdapter);

        rvMoviesList.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
            @Override
            protected void loadMoreItems() {
                isLoading = true;
                currentPage += 1;

                // mocking network delay for API  call
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        loadNextPage();
                    }
                }, 1000);
            }

            @Override
            public int getTotalPageCount() {
                return TOTAL_PAGES;
            }

            @Override
            public boolean isLastPage() {
                return isLastPage;
            }

            @Override
            public boolean isLoading() {
                return isLoading;
            }
        });

        // init service and load data
        movieService = Client.getClient().create(Service.class);

        loadFirstPage();

        return layout;
    }

    private void loadFirstPage() {
        Log.d(TAG, "LoadFirstPage");

        callPopularMovieApi()
                .enqueue(new Callback<MoviesResponse>() {
                    @Override
                    public void onResponse(Call<MoviesResponse> call, Response<MoviesResponse> response) {
                        // Got data send into adapter
                        List<MovieData> results = fetchResults(response);
                        pbMovies.setVisibility(View.GONE);
                        moviesAdapter.addAll(results);

                        if (currentPage <= TOTAL_PAGES) moviesAdapter.addLoadingFooter();
                        else isLastPage = true;
                    }

                    @Override
                    public void onFailure(Call<MoviesResponse> call, Throwable t) {
                        t.printStackTrace();
                    }
                });

    }

    private List<MovieData> fetchResults(Response<MoviesResponse> response) {
        MoviesResponse popularMovies = response.body();
        return popularMovies.getResults();
    }

    private void loadNextPage() {
        Log.d(TAG, "loadNextPage "+ currentPage);
        callPopularMovieApi()
                .enqueue(new Callback<MoviesResponse>() {
                    @Override
                    public void onResponse(Call<MoviesResponse> call, Response<MoviesResponse> response) {
                        moviesAdapter.removeLoadingFooter();
                        isLoading = false;

                        List<MovieData> results = fetchResults(response);
                        moviesAdapter.addAll(results);

                        if (currentPage != TOTAL_PAGES)moviesAdapter.addLoadingFooter();
                        else isLastPage = true;
                    }

                    @Override
                    public void onFailure(Call<MoviesResponse> call, Throwable t) {
                        t.printStackTrace();
                    }
                });
    }

    private Call<MoviesResponse> callPopularMovieApi() {
        return  movieService.getPopularMovies("f6602517b834e9ce06a48548f949e397", currentPage);
    }

}

这是我的 MainActivity

package com.ogi.layarkacamobile;

import android.content.Intent;
import android.provider.Settings;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;

import com.ogi.layarkacamobile.adapter.ViewPagerAdapter;
import com.ogi.layarkacamobile.fragment.MoviesFragment;
import com.ogi.layarkacamobile.fragment.TvShowsFragment;

public class MainActivity extends AppCompatActivity {

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

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ViewPager viewPager = findViewById(R.id.viewpager);
            setupViewPager(viewPager);

        TabLayout tabLayout = findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
    }

    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new MoviesFragment(), getResources().getString(R.string.movies_label));
        adapter.addFragment(new TvShowsFragment(), getResources().getString(R.string.tv_shows_label));
        viewPager.setAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.language_setting) {
            Intent mIntent = new Intent(Settings.ACTION_LOCALE_SETTINGS);
            startActivity(mIntent);
        }
        return super.onOptionsItemSelected(item);
    }
}

我正在尝试有关类似问题的建议,但它们都不起作用,因为我不知道如何在我的情况下实现它,非常感谢您提前

【问题讨论】:

  • 这是我整个 MainActivity 的正确答案:

标签: android android-activity fragment screen-orientation state-management


【解决方案1】:

片段:

您正在使用片段。因此,请防止在您可以使用的片段上发生方向变化时的破坏setRetainInstance(true)

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment when activity is re-initialized
        setRetainInstance(true);
    } 

活动:

当方向发生变化时,android会重新启动正在运行的Activity(调用onDestroy(),然后调用onCreate())。 如果你想处理内部活动,你不能使用:在特定活动的清单文件中。

对于 API 12 及以下版本:

android:configChanges="orientation"

如果您的目标是 API 13 或更高版本

android:configChanges="orientation|screenSize"

更新:在方向更改时保存片段状态

如果你想在activity内部使用onSaveInstanceState来保存fragment状态,你可以使用putFragment
在您的活动中,onSaveInstanceState 看起来像这样:

@Override
protected void onSaveInstanceState(Bundle outState) {
   getFragmentManager().putFragment(outState, MyFragment.TAG, mMyFragment);
}

Activity重启后获取Fragment状态,可以使用getFragment方法。

@Override
protected void onRestoreInstanceState(Bundle inState) {


   FragmentTransaction transaction =getFragmentManager().beginTransaction();

   if (inState != null) {
      mMyFragment = (MyFragment) getFragmentManager().getFragment(inState, MyFragment.TAG);
   } else {
      mMyFragment = new MyFragment();
      transaction.add(R.id.fragment, mMyFragment, MyFragment.TAG);
      transaction.commit();
   }

}

【讨论】:

  • 我正在使用它,但不幸的是,这个答案被我的编码训练营拒绝了,我必须使用 bundle savedinstancestate 来解决我的问题,而不是使用这个 android:configChanges="orientation|screenSize"
  • 但是你的网络调用代码在fragment里面,你可以在fragment里面使用setRetainInstance(true)。
  • 我在答案中添加了 UPDATE 以将片段状态保存在 activty 中。
  • 我必须把这行代码@Override protected void onRestoreInstanceState(Bundle inState) { private void instantiateFragments(Bundle inState) { FragmentTransaction transaction =getFragmentManager().beginTransaction(); if (inState != null) { mMyFragment = (MyFragment) getFragmentManager().getFragment(inState, MyFragment.TAG); } else { mMyFragment = new MyFragment(); transaction.add(R.id.fragment, mMyFragment, MyFragment.TAG); transaction.commit(); } } }
  • onRestoreInstanceState() 方法。在您的 activity 中覆盖此方法。我刚刚更新了 onRestoreInstanceState() 方法的代码。请检查一下。
【解决方案2】:

使用 LiveData。它将缓存您的 Recyclerview 数据并在设备旋转时从内部缓存重新加载。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多