如何在使用 onRestoreInstanceState() 旋转后恢复 Recyclerview

How to restore Recyclerview after rotation with onRestoreInstanteState()

我有一个片段需要在屏幕旋转时恢复其包含的 RecyclerView。我一直在使用 onViewStateRestored() 和 onSaveInstantState() 的标准过程。但是,当我旋转屏幕时出现空点异常。如我的代码和下面的 logcat 所示,问题出现在 onCreate() 期间。任何关于我做错了什么的详细说明将不胜感激。

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
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.Toast;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.google.gson.Gson;

import org.json.JSONObject;

import static uk.co.my_package.weatherscan.Utils.getForecastEndPoint;


public class PlaceForecastListFragment extends Fragment {

    public static final String PAGERTABTITLE = "Forecast";
    private static final String CITYID = "weather_cityid";
    private static final String SEVENDAYS = "7";
    private static final String LIST_STATE_KEY = "list_state";
    private static final String TAG = PlaceForecastListFragment.class.getSimpleName();
    private LinearLayoutManager mLinearLayoutManager;
    private RecyclerView mRecyclerView;
    private Parcelable mListState;
    private ProgressDialog pDialog;
    private String mCityId;

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

    public static PlaceForecastListFragment newInstance(String cityid) {
        PlaceForecastListFragment fragment = new PlaceForecastListFragment();
        Bundle args = new Bundle();
        args.putString(CITYID, cityid);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mCityId = getArguments().getString(CITYID);
        }

        if (savedInstanceState == null) {
            // Shows message to user while makeJsonObjectRequest() is still running.
            pDialog = new ProgressDialog(getContext());
            pDialog.setMessage("Getting weather forecast...");
            pDialog.setCancelable(false);

            // Make JSON request
            makeJsonObjectRequest(mCityId);
        } else {
            // Problem arises here!!!!!!!!!!!!!!!!!!!!
            mLinearLayoutManager.onRestoreInstanceState(mListState);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_place_forecast_list, container, false);
        if (view instanceof RecyclerView) {
            Context context = view.getContext();
            mRecyclerView = (RecyclerView) view;
            mLinearLayoutManager = new LinearLayoutManager(context);
            mRecyclerView.setLayoutManager(mLinearLayoutManager);
        }
        return view;
    }

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

        if (savedInstanceState != null) {

            mListState = savedInstanceState.getParcelable(LIST_STATE_KEY);
            mRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);
        }
    }

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


        //mListState = mLinearLayoutManager.onSaveInstanceState();
        savedInstantState.putParcelable(LIST_STATE_KEY, mRecyclerView.getLayoutManager().onSaveInstanceState());


    }


    // TODO CBA: Move this method to its own class and call it from here. This will be more organized.
    /**
     * Method to make json object request
     */
    private void makeJsonObjectRequest(final String cityId) {
        showpDialog();
        String url = getForecastEndPoint(cityId, SEVENDAYS);
        JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
                url, null, new Response.Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                // Log response
                Log.d(TAG, response.toString());
                String responseString = String.valueOf(response);
                Gson gson = new Gson();
                ResponseForecastConditions responseForecastConditionsObj =
                        gson.fromJson(responseString, ResponseForecastConditions.class);
                mRecyclerView.setAdapter(new ForecastAdapter(responseForecastConditionsObj,
                        getContext()));
                // Hide dialog after information has been requested
                hidepDialog();
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                // Warn user
                Toast.makeText(getContext(),
                        "No internet connection", Toast.LENGTH_LONG).show();
                // hide the progress dialog
                hidepDialog();
            }
        });
        // Adding request to request queue
        AppController.getInstance().addToRequestQueue(jsonObjReq);
    }

    /**
     * Method for showing dialog
     */
    private void showpDialog() {
        if (!pDialog.isShowing())
            pDialog.show();
    }

    /**
     * Method for hiding dialog
     */
    private void hidepDialog() {
        if (pDialog.isShowing())
            pDialog.dismiss();
    }
}

下面是 logcat 输出:

    03-20 16:32:40.801 6371-6405/uk.co.my_package.weatherscan E/Surface: getSlotFromBufferLocked: unknown buffer: 0xab7cfcb0
03-20 16:32:40.823 6371-6371/uk.co.my_package.weatherscan D/AndroidRuntime: Shutting down VM
03-20 16:32:40.823 6371-6371/uk.co.my_package.weatherscan E/AndroidRuntime: FATAL EXCEPTION: main
                                                                              Process: uk.co.my_package.weatherscan, PID: 6371
                                                                              java.lang.RuntimeException: Unable to start activity ComponentInfo{uk.co.my_package.weatherscan/uk.co.my_package.weatherscan.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.LinearLayoutManager.onRestoreInstanceState(android.os.Parcelable)' on a null object reference
                                                                                  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                                                  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                                                                                  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4077)
                                                                                  at android.app.ActivityThread.-wrap15(ActivityThread.java)
                                                                                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1350)
                                                                                  at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                  at android.os.Looper.loop(Looper.java:148)
                                                                                  at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                  at java.lang.reflect.Method.invoke(Native Method)
                                                                                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                               Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.LinearLayoutManager.onRestoreInstanceState(android.os.Parcelable)' on a null object reference
                                                                                  at uk.co.my_package.weatherscan.PlaceForecastListFragment.onCreate(PlaceForecastListFragment.java:68)
                                                                                  at android.support.v4.app.Fragment.performCreate(Fragment.java:1951)
                                                                                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
                                                                                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
                                                                                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234)
                                                                                  at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2041)
                                                                                  at android.support.v4.app.Fragment.performCreate(Fragment.java:1964)
                                                                                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
                                                                                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
                                                                                  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234)
                                                                                  at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2041)
                                                                                  at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:163)
                                                                                  at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:332)
                                                                                  at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:74)
                                                                                  at uk.co.my_package.weatherscan.MainActivity.onCreate(MainActivity.java:15)
                                                                                  at android.app.Activity.performCreate(Activity.java:6237)
                                                                                  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
                                                                                  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
                                                                                  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                                                                                  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4077) 
                                                                                  at android.app.ActivityThread.-wrap15(ActivityThread.java) 
                                                                                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1350) 
                                                                                  at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                  at android.os.Looper.loop(Looper.java:148) 
                                                                                  at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                                                  at java.lang.reflect.Method.invoke(Native Method) 
                                                                                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                                                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
03-20 16:33:58.373 6371-6378/uk.co.my_package.weatherscan W/art: Suspending all threads took: 24.263ms
03-20 16:34:04.875 6371-6378/uk.co.my_package.weatherscan W/art: Suspending all threads took: 17.116ms
03-20 16:36:28.696 6371-6378/uk.co.my_package.weatherscan W/art: Suspending all threads took: 15.452ms
03-20 16:37:40.836 6371-6371/? I/Process: Sending signal. PID: 6371 SIG: 9

mLinearLayoutManageronCreate 中为空,因为您在 onCreateView() 中创建了它。在 onCreate 中创建实例并在 onCreateView 中重复使用它。

I have a fragment that needs to restore the its containing RecyclerView upon screen rotation. I've been using the standard procedure with onViewStateRestored() and onSaveInstantState(). However, I'm getting a null point exception when I rotate the screen.

你做错了。旋转变化不需要保存layoutManager,每次实例化即可。如果您有任何其他 DATA 保存它们并使用它们来创建您的布局管理器。