Android
Kotlin

ViewHolderパターンを使っている場合、getView()の実装を一行にできるという話

More than 1 year has passed since last update.

最初におことわりですが、実用的な話ではないです。

AdapterのgetView()

Javaで書く場合は、だいたいこんな風になると思います。

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

            if (view == null) {
                view = getLayoutInflater().inflate(R.layout.hoge, parent, false);
                view.setTag(new ViewHolder(view));
            }
            ViewHolder holder = (ViewHolder) view.getTag();
            holder.update((Hoge) getItem(position));

            return view;
        }

これを、素直にKotlinにすると

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            var view = convertView

            if (view == null) {
                view = getLayoutInflater().inflate(R.layout.hoge, parent, false)
                view!!.tag = ViewHolder(view)
            }
            val holder = view.tag as ViewHolder
            holder.update(getItem(position) as Hoge)

            return view
        }

となります。

Nullableなvarはイヤん

このなかの、viewという変数は、varなView?型の変数です。
Kotlinの哲学は、valであるべき、NonNullであるべきというところにあると思うので、これをやっつけます。

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            val view = convertView ?: getLayoutInflater().inflate(R.layout.hoge, parent, false).apply { tag = ViewHolder(this) }

            val holder = view.tag as ViewHolder
            holder.update(getItem(position) as Hoge)

            return view
        }

いい感じです。
エルビス演算子とか、applyメソッドとかは便利です。
厳密に言えば、inflate()の返値がnullでないということは言語的に保証されているわけではないのですが、実用上、差し支えないでしょう。

実用的なのはこのあたりまでで、ここから先は、やればできるよという領域になります。
実際、自分で使っているのはこの形です。

asは()でくくりやすい

Javaのキャストと異なり、Kotlinのasを使ったキャストは、カッコでくくっても可読性が悪くならないので、やってみます。

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
            val view = convertView ?: getLayoutInflater().inflate(R.layout.hoge, parent, false).apply { tag = ViewHolder(this) }

            (view.tag as ViewHolder).update(getItem(position) as Hoge)

            return view
        }

これがJavaだと、

            ((ViewHolder) view.getTag()).update((Hoge) getItem(position));

カッコが多くなりすぎて使う気になれません。

仕上げのapply

ここまで来れば、一行でまとめたくなるのもやむなしです。( なくない

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View = (convertView ?: getLayoutInflater().inflate(R.layout.hoge, parent, false).apply { tag = ViewHolder(this) }).apply { (tag as ViewHolder).update(getItem(position) as Hoge) }

どやぁ!

やり過ぎですね。

まとめ

  • ?: は気が利くやつ
  • apply{} は便利
  • as はビューリホー

みんなもKotlinに乗り換えよう!