Skip to content
This repository was archived by the owner on Jun 23, 2022. It is now read-only.

Commit 1e95ccd

Browse files
author
Lyla
committed
5.12 Coding Task to Restore scroll position on rotation (quiz)
1 parent 57b2926 commit 1e95ccd

File tree

1 file changed

+51
-11
lines changed

1 file changed

+51
-11
lines changed

app/src/main/java/com/example/android/sunshine/app/ForecastFragment.java

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
* Encapsulates fetching the forecast and displaying it as a {@link ListView} layout.
3838
*/
3939
public class ForecastFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
40+
private ForecastAdapter mForecastAdapter;
41+
42+
private ListView mListView;
43+
private int mPosition = ListView.INVALID_POSITION;
44+
45+
private static final String SELECTED_KEY = "selected_position";
4046

4147
private static final int FORECAST_LOADER = 0;
4248
// For the forecast view we're showing only a small subset of the stored data.
@@ -71,8 +77,6 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
7177
static final int COL_COORD_LAT = 7;
7278
static final int COL_COORD_LONG = 8;
7379

74-
private ForecastAdapter mForecastAdapter;
75-
7680
/**
7781
* A callback interface that all activities containing this fragment must
7882
* implement. This mechanism allows activities to be notified of item
@@ -116,17 +120,18 @@ public boolean onOptionsItemSelected(MenuItem item) {
116120
@Override
117121
public View onCreateView(LayoutInflater inflater, ViewGroup container,
118122
Bundle savedInstanceState) {
119-
// The CursorAdapter will take data from our cursor and populate the ListView.
123+
124+
// The ForecastAdapter will take data from a source and
125+
// use it to populate the ListView it's attached to.
120126
mForecastAdapter = new ForecastAdapter(getActivity(), null, 0);
121127

122128
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
123129

124130
// Get a reference to the ListView, and attach this adapter to it.
125-
ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
126-
listView.setAdapter(mForecastAdapter);
127-
131+
mListView = (ListView) rootView.findViewById(R.id.listview_forecast);
132+
mListView.setAdapter(mForecastAdapter);
128133
// We'll call our MainActivity
129-
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
134+
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
130135

131136
@Override
132137
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
@@ -140,8 +145,21 @@ public void onItemClick(AdapterView<?> adapterView, View view, int position, lon
140145
locationSetting, cursor.getLong(COL_WEATHER_DATE)
141146
));
142147
}
148+
mPosition = position;
143149
}
144150
});
151+
152+
// If there's instance state, mine it for useful information.
153+
// The end-goal here is that the user never knows that turning their device sideways
154+
// does crazy lifecycle related things. It should feel like some stuff stretched out,
155+
// or magically appeared to take advantage of room, but data or place in the app was never
156+
// actually *lost*.
157+
if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) {
158+
// The listview probably hasn't even been populated yet. Actually perform the
159+
// swapout in onLoadFinished.
160+
mPosition = savedInstanceState.getInt(SELECTED_KEY);
161+
}
162+
145163
return rootView;
146164
}
147165

@@ -163,12 +181,29 @@ private void updateWeather() {
163181
weatherTask.execute(location);
164182
}
165183

184+
@Override
185+
public void onSaveInstanceState(Bundle outState) {
186+
// When tablets rotate, the currently selected list item needs to be saved.
187+
// When no item is selected, mPosition will be set to Listview.INVALID_POSITION,
188+
// so check for that before storing.
189+
if (mPosition != ListView.INVALID_POSITION) {
190+
outState.putInt(SELECTED_KEY, mPosition);
191+
}
192+
super.onSaveInstanceState(outState);
193+
}
194+
166195
@Override
167196
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
168-
String locationSetting = Utility.getPreferredLocation(getActivity());
197+
// This is called when a new Loader needs to be created. This
198+
// fragment only uses one loader, so we don't care about checking the id.
199+
200+
// To only show current and future dates, filter the query to return weather only for
201+
// dates after or including today.
169202

170203
// Sort order: Ascending, by date.
171204
String sortOrder = WeatherContract.WeatherEntry.COLUMN_DATE + " ASC";
205+
206+
String locationSetting = Utility.getPreferredLocation(getActivity());
172207
Uri weatherForLocationUri = WeatherContract.WeatherEntry.buildWeatherLocationWithStartDate(
173208
locationSetting, System.currentTimeMillis());
174209

@@ -181,12 +216,17 @@ public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
181216
}
182217

183218
@Override
184-
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
185-
mForecastAdapter.swapCursor(cursor);
219+
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
220+
mForecastAdapter.swapCursor(data);
221+
if (mPosition != ListView.INVALID_POSITION) {
222+
// If we don't need to restart the loader, and there's a desired position to restore
223+
// to, do so now.
224+
mListView.smoothScrollToPosition(mPosition);
225+
}
186226
}
187227

188228
@Override
189229
public void onLoaderReset(Loader<Cursor> cursorLoader) {
190230
mForecastAdapter.swapCursor(null);
191231
}
192-
}
232+
}

0 commit comments

Comments
 (0)