Android:ListViewの画面回転と復元

More than 1 year has passed since last update.


はじめに

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 で重大な不具合が発生する可能性があります。

そのため、その解決策を 別の記事 で紹介したいと思います。