My app is a master/detail flow based app that fetches pictures from reddit, displays them in a recyclerView, and upon clicking opens a detail view where you can set the picture as a wallpaper. I can't figure out how to get phone rotation to work properly. My recyclerView is returning null in my onViewStateRestored method when the phone is rotated and is crashing my app.
I've looked through various tutorials and examples, and lots of stack overflow questions, but can't find a specific answer.
Here is the fragment code I'm dealing with:
private DataAdapter adapter;
private RecyclerView recyclerView;
private OnFragmentInteractionListener mListener;
private static final String BUNDLE_RECYCLER_LAYOUT = "ListFragment.recycler.layout";
public View myView;
public ListFragment() {
// Required empty public constructor
}
public static ListFragment newInstance() {
ListFragment fragment = new ListFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
GetDataService service = RetrofitInstance.getRetrofitInstance().create(GetDataService.class);
Call<Article> call = service.getData();
Log.wtf("Url Called", call.request().url() + "");
call.enqueue(new Callback<Article>() {
@Override
public void onResponse(Call<Article> call, Response<Article> response) {
Log.wtf("Response body", response.body().getData().getChildren().toString());
generateDataList(response.body().getData().getChildren());
}
@Override
public void onFailure(Call<Article> call, Throwable t) {
Toast.makeText(getActivity(), "Something went wrong...Please try again later!", Toast.LENGTH_LONG).show();
t.printStackTrace();
}
});
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(myView == null) {
myView = inflater.inflate(R.layout.fragment_list, container, false);
}
// Inflate the layout for this fragment
return myView;
}
private void generateDataList(List<Child> dataList) {
recyclerView = (RecyclerView) getView().findViewById(R.id.recycler_view_data_list);
dataList.subList(0, 2).clear();
adapter = new DataAdapter(getActivity(), dataList);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, recyclerView.getLayoutManager().onSaveInstanceState());
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if(savedInstanceState != null) {
Parcelable savedRecyclerInstanceState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
recyclerView.getLayoutManager().onRestoreInstanceState(savedRecyclerInstanceState);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
And here is the stack trace I get when I rotate the phone:
Process: com.botsone.amoleddit, PID: 5097
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView$LayoutManager.onRestoreInstanceState(android.os.Parcelable)' on a null object reference
at com.botsone.amoleddit.fragment.ListFragment.onViewStateRestored(ListFragment.java:129)
at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:543)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:907)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2656)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2610)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:542)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1470)
at android.app.Activity.performStart(Activity.java:7184)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3147)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1955)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:7029)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)