アマチュアでもできるKotlin-Android2「RecycleViewをKotlinで」

RecycleViewを書いてみよう

RecycleView全然手出ししてなかったのでやってみようという単純かつおばかな理由でKotlinで実装する事にしました。以下資料

Developer http://developer.android.com/intl/ja/reference/android/support/v7/widget/RecyclerView.html

チュートリアル http://developer.android.com/intl/ja/training/material/lists-cards.html

Googleのサンプル https://github.com/googlesamples/android-RecyclerView

や〜Googleデベロッパーは英語が簡単でいいな〜、This is a Pen〜I am Pen〜レベルの英語。Appleデベロッパー行った時英語の難しさで(T . T)泣きましたもん。基本的にはlistViewみたいにAdapter作ってxmlはめればいいんですが多少注意が必要です

調べれば調べるほど「普通のやつはListViewでいいんじゃね?」と思いました。 http://sys1yagi.hatenablog.com/entry/2015/01/09/090000

Kotlinで実践的にAndroid実装する時のポイント

Kotlinは覚えやすいけど当然Javaと違うので幾つか注意点抑えとかないとです

Nullの扱い方

NullSaftyな言語なんで当然扱い方にルールがあります。@yy_yankさんのこのページが大変参考になりました。Swiftでもこういうページが欲しかった

【Nullいことしてんじゃねぇ】声に出して読みたいKotlin http://yyyank.blogspot.jp/2014/12/nullkotlin-ktac2014.html#Pbp3acE.twitter_tweet_box_count

・Nullじゃなけりゃ手短に(If not null shorthand)

・Null如何にせよ手短に(If not null and else shorthand)

・Nullじゃなけりゃ、やっちまえ(Execute if not null)

・ユー、whenで返しちゃいなよ(Return on when statement)

・ユー、ifで返しちゃいなよ(Return on if statement)

・ユー、tryブロックごと返しちゃいなよ(Return on try catch block)

・非Nullだってばよ(Not-Null)

・マップにお任せ(Storing Properties in a Map)

・Null安全(Null Safety)

・安全なキャスト(Safe Casts)

・安全呼び出し(Safe Calls)

エルビス演算子(Elvis Operator)

コンストラクタ

Kotlinのコンストラクタはめちゃ簡単、

class CustomAdapter(cardview : Array<card_View>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>(){
    protected val mCardView : Array<card_View>  = cardview

セカンダリ及びsuperつきだとこんな感じ

class ViewHolder : RecyclerView.ViewHolder {
        constructor(v: View):super(v) {}
}

ちょっと面食らうくらいシンプルなんで逆に迷いました。JavaからKotlinで一番面食らうかも。詳しくは以下のサイトで解説されているのでご一読をhttp://dev.classmethod.jp/smartphone/android-kotlin-introduction-04/

スコープ関数

Kotlinに用意されてるパッケージの中でインスタンスをいじる時に用意される便利関数。エバンジェリスト@ngsw_taroさんの解説が詳しい。

デベロッパーのサイトでもスコープ関数以外もあるまとまった解説がありました。

詰まった時はAndroidStudioのコード補完が教えてくれます。コード補完でメソッド名にあたりをつけたらググってデベロッパーなり優秀な方がの記事で調べてます。実装の段階になればNullチェックに使うlet、インスタンスをいじるapplyあたりは必ず使う感じです

実装コード見本

以上の点を抑えつつ実装に入ります。今回は例としてRecycleViewのAdapterクラスのコードを晒してみます

class CustomAdapter(cardview : Array<card_View>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>(){

    protected val mCardView : Array<card_View>  = cardview

    class ViewHolder : RecyclerView.ViewHolder {
        constructor(v: View):super(v) {
            //SAM変換がもろにきいてます
            v.setOnClickListener { print("Element " + getAdapterPosition() + " clicked.") }
        }
        //KotlinExtentionを使ってるのでfindViewByIdはなし
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder? {
        val v : View = LayoutInflater.from(parent.context).inflate(R.layout.recycle_card,parent,false)
        return ViewHolder(v)
    }


    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Log.d("test",mCardView[position].card_title)
        //setter,getterは書かなくてもインスタンスについてくる
        holder.itemView.card_title.text = mCardView[position].card_title
        holder.itemView.caption1.text = mCardView[position].caption1
        holder.itemView.caption2.text = mCardView[position].caption2
    }

    override fun getItemCount(): Int {
        return mCardView.count()
    }
    
}

コード少ない!軽いプロジェクト1個書いたんですが体感でコード量は2/3に感じます。同じ内容をJavaでもかいてみます

public class CustomAdapterJava extends RecyclerView.Adapter<CustomAdapterJava.ViewHolder>{

    private ArrayList<card_View> mCardview = null;
    private  static final String TAG = "CustomAdapterJava";

    public CustomAdapterJava(ArrayList<card_View> cardview){
        mCardview = cardview;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private TextView mTitle = null;
        private TextView mcaption1 = null;
        private TextView mcaption2 = null;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG, "Element " + getAdapterPosition() + " clicked.");
                }
            });
            //以下三行はDataBindingしてればいらない
            mTitle = (TextView)itemView.findViewById(R.id.card_title);
            mcaption1 = (TextView)itemView.findViewById(R.id.caption1);
            mcaption2 = (TextView)itemView.findViewById(R.id.caption2);
        }

        public TextView getmTitle(){return mTitle;}
        public TextView getMcaption1(){return mcaption1;}
        public TextView getMcaption2(){return mcaption2;}
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.recycle_card, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.getmTitle().setText(mCardview.get(position).getCard_title());
        holder.getMcaption1().setText(mCardview.get(position).getCaption1());
        holder.getMcaption2().setText(mCardview.get(position).getCaption2());
    }

    @Override
    public int getItemCount() {
        return mCardview.size();

    }
}

setter,getterいらないだけでもかなり可読性違うと思います。以上AndroidをKotlinで実装する際の最初のポイントっぽいのをまとめてみました エミュレーターで実行したらこんな感じです。 f:id:poTracy:20160423200457p:plain