0
0

More than 3 years have passed since last update.

ListView用のカスタムアダプターの中身を逆順にするときにおこった問題について

Last updated at Posted at 2021-03-25

問題のコード

ListWorkActivity.java
public class ListWorkActivity extends AppCompatActivity implements View.OnClickListener {
    private ArrayList<Record> listItems = new ArrayList<>();
    private DateArrayAdapter arrayAdapter;
    private ListView listView;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);
//listViewにlistItemsをセットしたい
        listView = findViewById(R.id.listView);
        {...}
//nullじゃないlistView(ここは省略)と自作のDateArrayAdapter 
        arrayAdapter = new DateArrayAdapter(this, R.layout.date_list, listItems);
        listView.setAdapter(arrayAdapter);
   }


//menu内のボタンをクリックするとListViewの中身が逆順になるようにしたい
public boolean onOptionsItemSelected(MenuItem menuItem){
        int item = menuItem.getItemId();
        switch (item) {
            {...}
            case R.id.menu_button:
                //button
                //逆順にする
                Collections.reverse(listItems);
                arrayAdapter.clear();
                arrayAdapter.addAll(listItems);
                arrayAdapter.notifyDataSetChanged();
                break;
        }
        return false;
    }

自作のアダプタークラス

ListViewにカスタマイズしたレイアウトで要素を表示するためのクラスです。

DateArrayAdapter.java
public class DateArrayAdapter extends ArrayAdapter<Record> {

    private int mResource;
    private List<Record> mItems;
    private LayoutInflater mInflater;

    /**
     * コンストラクタ
     * @param context コンテキスト
     * @param resource レイアウトファイルのリソースID
     * @param items リストビューの要素
     */

    public DateArrayAdapter(Context context, int resource, ArrayList<Record> items){
        super(context, resource, items);

        mResource = resource;
        mItems = items; //ArrayList -> List
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    }


    @Override
    public int getCount() {
        return mItems.size();
    }

    @Override
    public Record getItem(int position) {
        return mItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;

        if (convertView != null){
            view = convertView;
        }else{
            view = mInflater.inflate(mResource, null);
        }

        Record record;
        //リストビューに表示する要素を取得
        record = getItem(position);

        //date
        TextView textViewDate = view.findViewById(R.id.textViewDate_DateLayout);
        textViewDate.setText(record.getDate());

        //work
        TextView textViewWork = view.findViewById(R.id.textViewWork_DateLayout);
        textViewWork.setText(record.getWork());

        //memo
        TextView textViewMemo = view.findViewById(R.id.textViewMemo_DateLayout);
        textViewMemo.setText(record.getMemo());

        return view; //may not be null
    }
}

Record.javaはデータ格納用のクラスです
Record.java
public class Record {
    //日付、work、メモを格納するクラス
    private String date;
    private String work;
    private String memo;

    //空のコンストラクタ
    public Record(){ }

    //コンストラクタ
    public Record(String date, String work, String memo){
        this.date = date;
        this.work = work;
        this.memo = memo;
    }


    public String getDate() {
        return date;
    }

    public String getWork() {
        return work;
    }

    public String getMemo() {
        return memo;
    }
}

起こった問題について

やりたかったこと

・listViewの中身を逆順にして表示する

実際はどうなったか

・clear()をするとlistItemsが消えた

//onOptionsItemSelected内の処理
Collections.reverse(listItems); //ここでlistItemsを逆順にすることには成功
arrayAdapter.clear(); //listItems の要素数が0になる = listItemsが消えた!?
arrayAdapter.addAll(listItems);
arrayAdapter.notifyDataSetChanged();

何が問題だったか

スクリーンショット 2021-03-25 114518.png

これによると、arrayAdapterのコンストラクタでcollectionを渡してしまうと、そのリストは変更不可能になってしまい、clear()を使うと例外が発生するということです。
DateArrayAdapterのコンストラクタではsuper(context, resource, items) (items = listView)を呼び出していたのでうまくいかなかったわけです。

解決法

ArrayAdapterにはほかにもコンストラクタがあるので、T[]を使わないコンストラクタをt作りました。

DateArrayAdapter.java
public class DateArrayAdapter extends ArrayAdapter<Record> {

    private int mResource;
    private List<Record> mItems;
    private LayoutInflater mInflater;

    /**
     * コンストラクタ
     * @param context コンテキスト
     * @param resource レイアウトファイルのリソースID
     * @param items リストビューの要素
     */

//問題のコンストラクタ。引数にリストを渡している。
    public DateArrayAdapter(Context context, int resource, ArrayList<Record> items){
        super(context, resource, items);

        mResource = resource;
        mItems = items; //ArrayList -> List
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    }

//新しいコンストラクタ。引数にarrayListは渡していない。
    public DateArrayAdapter(Context context, int resource){
        super(context, resource);

        mResource = resource;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

//新しいコンストラクタではmItemsを設定できないので、セッターを用いる。
//これがないとほかのメソッドがmItemsを使えなくて動かなくなるので注意
    public void setItems(List<Record> mItems) {
        this.mItems = mItems;
    }

//あとは同じです。
    @Override
    public int getCount() {
        return mItems.size();
    }

    {...}
}
ListWorkActivity.java
//アダプターをセットするところがこんな感じに変わる
arrayAdapter = new DateArrayAdapter(this, R.layout.date_list);
arrayAdapter.addAll(listItems);
arrayAdapter.setItems(listItems);
listView.setAdapter(arrayAdapter);

ほかにいい解決法がありそうなら教えていただけると嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0