TheNodeCommode TheNodeCommode - 3 months ago 27
Java Question

NPE on fragment recreation. Button is null after orientation change in fragment

I have read all the other topics related to this issue and none seem to be helping me solve the problem.

I am doing some background task in an asynctask that needs to persist on orientation change (configChanges). I have gotten the data to persist I believe by using fragments and setRetainInstance(true), but my buttons (Im assuming any views really) are being set to null on recreation of the fragment on orientation change. This is causing a null pointer error when I try to operate on the buttons reference after orientation has change (fragment has been recreated).

I have tried wrapping the button and calls on the button in a statement to check if the bundle is null. This stops the crash but does not allow for the button to be used again on recreation of the fragment.

The following class extends Fragment.

@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);

currentActivity = super.getActivity();

}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onActivityCreated(Bundle)");
super.onActivityCreated(savedInstanceState);

simpleForecastIntent = new Intent(currentActivity, SimpleForecastActivity.class);

Button fetchDataButton = (Button) currentActivity.findViewById(R.id.fetchDataButton);

if (savedInstanceState == null) {
fetchDataButton.setOnClickListener(fetchDataButtonListener);
fetchDataButton.setTransformationMethod(null);
}

locationManager = (LocationManager)
currentActivity.getSystemService(Context.LOCATION_SERVICE);

if (isTaskRunning) {
progressDialog = ProgressDialog.show(currentActivity, "Fetching data", "Please wait...");
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView(LayoutInflater, ViewGroup, Bundle)");

return inflater.inflate(R.layout.main_menu, container, false);
}


main_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.MainActivity">

<include layout="@layout/toolbar" />

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<Button
android:id="@+id/fetchDataButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/locationField"
android:text="@string/fetch_weather_data"
android:layout_centerHorizontal="true" />

<EditText
android:id="@+id/locationField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/enter_location"
android:layout_alignEnd="@+id/fetchDataButton"
android:layout_alignLeft="@+id/fetchDataButton"
android:layout_alignRight="@+id/fetchDataButton"
android:layout_alignStart="@+id/fetchDataButton"
android:inputType="textPostalAddress" />

<ListView
android:id="@+id/previousLocationsList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/fetchDataButton"
android:layout_centerHorizontal="true" />
</RelativeLayout>

</LinearLayout>


I have spent far too many hours on something so trivial and really need a bump in the correct direction. How can I get the button to not be null on recreation of fragment?

EDIT SOLVED:
I was using the disposed of activity's context to find the view of the button. Instead of the new activities view context.

@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);

currentActivity = super.getActivity();

}

Answer

The problem is that you are referencing your button in onActivityCreated instead of onCreateView. On orientation change, the view gets torn down and then recreated. You should override onCreateView and maintain the reference to your button from there.

Comments