目次
1. この記事の目的
KotlinがAndroid開発言語として正式にサポートされたということで、勉強がてらJavaのソースをKotlinに翻訳します。
翻訳するJavaのソースは下記の「リストとカードの作成」から拝借しました。
2. JavaのActivityのソース
「リストとカードの作成」にあるActivityのソースは下記の通りです。
public class MyActivity extends Activity { private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_activity); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); // use a linear layout manager mLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); // specify an adapter (see also next example) mAdapter = new MyAdapter(myDataset); mRecyclerView.setAdapter(mAdapter); } ... }
onCreateの時に、mRecyclerViewにmLayoutManagerとmAdapterをセットしています。
3. KotlinのActivityのソース
先ほどのJavaのコードをKotlinに翻訳する上で必要になる知識は下記の2つです。
- Null許容型
- キャスト
3.1. KotlinにおけるNull許容型
KotlinではNullを代入できるかどうかを型で宣言することができます。
// non nullable type, cannot put null mRecyclerView: RecyclerView = null // Error! // nullable type, can put null mRecyclerView: RecyclerView? = null // Okay!
また、Nullチェックも非常にスマートに記述できます。
// if null, setAdapter will not executed, no error will thrown mRecyclerView?.setAdapter(mAdapter); // if null, setAdapter will not executed, runtime error will thrown mRecyclerView!!.setAdapter(mAdapter);
3.2. キャスト
Kotlinではasキーワードを使ってキャストを行います。
// if findViewById returns null, runtime error will thrown mRecyclerView = findViewById(R.id.recycler) as RecyclerView // if findViewById returns null, mRecyclerView equals null, no error will thrown mRecyclerView = findViewById(R.id.recycler) as? RecyclerView
3.3. 最終的に翻訳されたKotlinのActivityのソース
Null許容型とキャストの方法を踏まえて翻訳すると、下記のようになりました。
class MainActivity : AppCompatActivity() { private var mTextMessage: TextView? = null private var mRecyclerView: RecyclerView? = null private var mAdapter: MyAdapter? = null private var mLayoutManager: RecyclerView.LayoutManager? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mTextMessage = findViewById(R.id.message) as TextView mRecyclerView = findViewById(R.id.main_recycler) as RecyclerView mRecyclerView?.setHasFixedSize(true) mLayoutManager = LinearLayoutManager(this) mRecyclerView?.layoutManager = mLayoutManager val myDataset: Array<String> = Array(10, {i: Int -> (i * i).toString() }) mAdapter = MyAdapter(myDataset) mRecyclerView?.setAdapter(mAdapter) val navigation = findViewById(R.id.navigation) as BottomNavigationView navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener) } }
4. JavaのAdapterのソース
「リストとカードを作成する」より拝借したAdapterのソースは下記の通りです。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private String[] mDataset; public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(TextView v) { super(v); mTextView = v; } } public MyAdapter(String[] myDataset) { mDataset = myDataset; } @Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.my_text_view, parent, false); ... ViewHolder vh = new ViewHolder(v); return vh; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mTextView.setText(mDataset[position]); } @Override public int getItemCount() { return mDataset.length; } }
RecyclerView.Adapterを継承したMyAdapterは、インナークラスにViewHolderを持っています。
インナークラスはただ渡されたTextViewを保持するのみです。
MyAdapterは必要があればLayoutInflatorでレイアウトを増やしたり、データをセットします。
5. KotlinのAdapterのソース
先ほどのJavaのソースコードを翻訳するのに必要なのは下記の2つです。
- コンストラクタの書き方
- companion object
5.1. Kotlinにおけるコンストラクタの書き方
Kotlinではクラス名のすぐ後にコンストラクタ(プライマリコンストラクタ)を書くことができます。
class SampleClass(message: String) { val mMessage: String = message }
このようにすると、フィールド変数に一度Nullが入ることもなく、気分がいいです。
もちろん複数のコンストラクタを定義することもできます。
その際は2つめ以降のコンストラクタをセカンダリコンストラクタといいます。
5.2. Kotlinにおけるcompanion object
Kotlinにはstaticというキーワードがありません。
staticと似たことを実現するのは、companion objectをつかいます。
class SampleClass(message: String) { val mMessage: String = message companion object { val Constants: Int = 0 } }
このようにクラスの中にcompanion objectを持つことで、Constantsという定数を定義できます。
5.3. 最終的に翻訳されたKotlinのAdapterのソース
class MyAdapter(myDataset: Array<String>): RecyclerView.Adapter<MyAdapter.ViewHolder>() { val mDataset: Array<String> = myDataset class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { var mTextView: TextView? = itemView.findViewById(R.id.info_text) as? TextView companion object Factory { fun create(v: TextView): ViewHolder = ViewHolder(v) } } override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder { val v: View = LayoutInflater.from(parent?.context) .inflate(R.layout.my_text_view, parent, false) val vh: ViewHolder = ViewHolder(v) return vh } override fun onBindViewHolder(holder: ViewHolder?, position: Int) { holder?.mTextView?.text = mDataset[position] } override fun getItemCount(): Int = mDataset.size }
6. まとめ
この記事ではAndroidアプリのJavaのソースを読んで、Kotlinに翻訳しました。
このようなちょっとしたソースコードを書いてみるだけでも、Kotlinのいいところが見つかりました。
Null許容型とNullチェックは簡潔で分かりやすくメリットが大きいです。