はじめに
ListViewを単純に実装した場合、画面回転しても、表示していたアイテムは保持されません。
そのため画面回転するたびに、アイテムを取得し直す必要があったり、スクロール位置が最上部に戻ってしまったり、といった問題が発生します。
この記事では、画面回転しても、スクロール位置はそのままに、アイテムを取得し直すこともなく、ListViewを復元する方法を記載します。
後述のソースコードについて
ListViewを使ってユーザ情報(UserListAdapterItem)を表示します。
今回の記事に関係ない以下の内容についてはソースコードに記載しておりません。
- UserListAdapterItemの中身
- ユーザ情報の一覧を表示するためのカスタムアダプター(UserListAdapter)のgetViewメソッド
- ListViewのアイテムのレイアウトXML
- UserListAdapterItemのリストの新規生成
ソースコード
ListViewActivity.java
/**
* ListViewを表示しているActivity
*/
public class ListViewActivity extends AppCompatActivity {
private ListView mUserListView;
private UserListAdapter mUserListAdapter;
/**
* ListViewのアイテムをBundleに保存するためのキー
*/
private static final String BUNDLE_KEY_ITEM_LIST = "item_list";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
// ListViewとそのAdapterの初期化
mUserListView = (ListView) findViewById(R.id.list_user);
mUserListAdapter = new UserListAdapter(this, new ArrayList<UserListAdapterItem>());
mUserListView.setAdapter(mUserListAdapter);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// ListViewのアイテムを復元する
if (savedInstanceState != null && !savedInstanceState.isEmpty()) {
List<UserListAdapterItem> itemList = (List) savedInstanceState.getSerializable(BUNDLE_KEY_ITEM_LIST);
mUserListAdapter.setItemList(itemList);
}
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Adapterが空だった場合はListViewに表示するアイテムを新規に取得する
if (mUserListAdapter.isEmpty()) {
List<UserListAdapterItem> itemList = createUserListAdapterItemList();
mUserListAdapter.setItemList(itemList);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// 復元用にListViewのアイテムを保存する
outState.putSerializable(BUNDLE_KEY_ITEM_LIST, mUserListAdapter.getItemList());
super.onSaveInstanceState(outState);
}
/**
* アイテムを生成する処理
*
* @return
*/
private List<UserListAdapterItem> createUserListAdapterItemList() {
// 記事に関係ないため省略
}
}
activity_list_view.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- ListViewActivityのレイアウト -->
<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=".view.activity.ListViewActivity">
<ListView
android:id="@+id/list_user"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
UserListAdapter.java
/**
* ListViewでユーザ情報(UserListAdapterItem)を表示するためのカスタムアダプター
*/
public class UserListAdapter extends ArrayAdapter<UserListAdapterItem> {
private LayoutInflater mInflater;
public UserListAdapter(Context context, List<UserListAdapterItem> objects) {
super(context, 0, objects);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 記事に関係ないため省略
}
/**
* Adapter内のアイテムをすべて取得する。
* 返却する型がArrayListなのは、Serializableを継承しているため。
*
* @return
*/
public ArrayList<UserListAdapterItem> getItemList() {
ArrayList<UserListAdapterItem> itemList = new ArrayList<>();
for (int i = 0, size = getCount(); i < size; i++) {
UserListAdapterItem item = getItem(i);
itemList.add(item);
}
return itemList;
}
/**
* Adapterにアイテムのリストを設定する。
*
* @param itemList
*/
public void setItemList(List<UserListAdapterItem> itemList) {
clear();
addAll(itemList);
}
}
おわりに
上記のように実装いただければ、画面回転した時に、回転前に表示していたListViewの内容を復元することができます。
しかしこちらの方法では、Android 7 で重大な不具合が発生する可能性があります。
そのため、その解決策を 別の記事 で紹介したいと思います。