先週のGoole I/O 2017で、KotlinがAndroidの公式言語の1つとなると、発表されました
Javaも残ります
Kotlinとは
- JVM言語(Javaと相互運用できる)
- 型推論
var str = "abc"
- null安全
var strNullable: String?
var strNotNull: String
- 関数型プログラミング
listOf(1, 2, 3).map { it * 2 }.filter { it > 2 }.forEach { print(it) }
実際のコードで紹介
- 画像とテキストのViewをグリッド表示する
- 各Viewは、スクロールin/outで再利用される
各Viewを作るコードで見てみます
static class ViewHolder {
TextView textView;
ImageView imageView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Viewを準備する
ViewHolder holder;
if (convertView == null) {
// convertViewがなかったら、xmlからViewを作る
convertView = LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null);
// パフォーマンスのため、各sub viewをHolderに保持し、Holder自体もViewに保持しておく
holder = new ViewHolder();
holder.imageView = (ImageView) convertView.findViewById(R.id.icon); // ちょっと遅い
holder.textView = (TextView) convertView.findViewById(R.id.text); // ちょっと遅い
convertView.setTag(holder);
} else {
// convertViewがあれば、再利用する。
holder = (ViewHolder) convertView.getTag();
}
// データをViewに反映する
Data data = getItem(position);
holder.imageView.setImageResource(data.imageId);
holder.textView.setText(data.textId);
return convertView;
}
internal class ViewHolder {
var textView: TextView? = null
var imageView: ImageView? = null
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
// Viewを準備する
val holder: ViewHolder
if (convertView == null) {
// convertViewがなかったら、xmlからViewを作る
convertView = LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null)
// パフォーマンスのため、各sub viewをHolderに保持し、Holder自体もViewに保持しておく
holder = ViewHolder()
holder.imageView = convertView.findViewById(R.id.icon) as ImageView // ちょっと遅い
holder.textView = convertView!!.findViewById(R.id.text) as TextView // ちょっと遅い
convertView.tag = holder
} else {
// convertViewがあれば、再利用する。
holder = convertView.tag as ViewHolder
}
// データをViewに反映する
val data = getItem(position)
holder.imageView!!.setImageResource(data.imageId)
holder.textView!!.setText(data.textId)
return convertView
}
data classで、fieldとconstructorを同時に定義
- internal class ViewHolder {
- var imageView: ImageView? = null
- var textView: TextView? = null
- }
+ data class ViewHolder(val textView: TextView, val imageView: ImageView)
constructorを使えば1行
- holder = ViewHolder()
- holder.imageView = convertView.findViewById(R.id.icon) as ImageView // ちょっと遅い
- holder.textView = convertView!!.findViewById(R.id.text) as TextView // ちょっと遅い
+ holder = ViewHolder(convertView.findViewById(R.id.text) as TextView, convertView.findViewById(R.id.icon) as ImageView)
Kotlin Android ExtensionによるfindViewByIdのwrapperを使う
- holder = ViewHolder(convertView.findViewById(R.id.text) as TextView, convertView.findViewById(R.id.icon) as ImageView)
+ holder = ViewHolder(convertView.text, convertView.icon)
いちいち、一次変数を使いたくない
also
// convertViewがなかったら、xmlからViewを作る
- view = LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null)
- view.tag = ViewHolder(it.text, it.icon)
+ view = LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null).also {
+ it.tag = ViewHolder(it.text, it.icon)
+ }
run
// データをViewに反映する
- val data = getItem(position)
- holder.imageView!!.setImageResource(data.imageId)
- holder.textView!!.setText(data.textId)
+ getItem(position).run {
+ holder.imageView.setImageResource(imageId)
+ holder.textView.setText(textId)
+ }
ifは式なので、直接代入する
- var view: View
- if (convertView == null) {
// convertViewがなかったら、xmlからViewを作る
- view = LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null).also {
+ var view: View = if (convertView == null) {
+ LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null).also {
// パフォーマンスのため、各sub viewをHolderに保持し、Holder自体もViewに保持しておく
it.tag = ViewHolder(it.text, it.icon)
}
} else {
// convertViewがあれば、再利用する。
- view = convertView
+ convertView
}
?: 演算子で、if-nullをなくす
- var view: View = if (convertView == null) {
- // convertViewがなかったら、xmlからViewを作る
- LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null).also {
+ var view: View = convertView ?: LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null).also {
// パフォーマンスのため、各sub viewをHolderに保持し、Holder自体もViewに保持しておく
it.tag = ViewHolder(it.text, it.icon)
}
- } else {
- // convertViewがあれば、再利用する。
- convertView
}
元のJavaコード
static class ViewHolder {
TextView textView;
ImageView imageView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Viewを準備する
ViewHolder holder;
if (convertView == null) {
// convertViewがなかったら、xmlからViewを作る
convertView = LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null);
// パフォーマンスのため、各sub viewをHolderに保持し、Holder自体もViewに保持しておく
holder = new ViewHolder();
holder.imageView = (ImageView) convertView.findViewById(R.id.icon); // ちょっと遅い
holder.textView = (TextView) convertView.findViewById(R.id.text); // ちょっと遅い
convertView.setTag(holder);
} else {
// convertViewがあれば、再利用する。
holder = (ViewHolder) convertView.getTag();
}
// データをViewに反映する
Data data = getItem(position);
holder.imageView.setImageResource(data.imageId);
holder.textView.setText(data.textId);
return convertView;
}
書き換えたKotlinコード
data class ViewHolder(val textView: TextView, val imageView: ImageView)
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
// Viewを準備する
val view: View = convertView ?: LayoutInflater.from(mContext).inflate(R.layout.dialog_grid_menu_item, null).also {
// パフォーマンスのため、各sub viewをHolderに保持し、Holder自体もViewに保持しておく
it.tag = ViewHolder(it.text, it.icon)
}
// データをViewに反映する
(view.tag as ViewHolder).let { (textView, imageView) ->
getItem(position).run {
textView.setText(textId)
imageView.setImageResource(imageId)
}
}
return view
}
thanks