Help us understand the problem. What is going on with this article?

KotlinでAndroid

More than 3 years have passed since last update.

Androidの勉強をしたいけどJavaが全然頭に入ってこないのでKotlinを使うことにしました。自分用の覚書です。

Kotlin

log

print("hogeohoge")
println("HOGEHOGE")
//=> hogehogeHOGEHOGE

改行するまで出力されません。最初、print()でログに表示されないので困ってました。

配列

listとかarrayとか。この辺、Java分かってないとダメっぽい。あとで調べる。

val list = listOf(0, 1, 2)
println(list.javaClass)
//=> class java.util.Arrays$ArrayList

val mutableList = mutableListOf(0, 1, 2)
println(mutableList.javaClass)
//=> class java.util.ArrayList

val array = arrayOf(0, 1, 2)
println(array.javaClass)
//=> class [Ljava.lang.Integer;

最後のカンマはエラーになる。個人的にこれは痛い。

val list = listOf(0, 1, 2, 3, 4,)

immutable read-only

val list = listOf(0, 1, 2, 3, 4)
//list[2] = 0 //エラー
println(list)
//=> [0, 1, 2, 3, 4]

varにしても中身はimmutable read-only。

var list = listOf(0, 1, 2, 3, 4)
//list[2] = 0 //エラー

なぜimmutableではないかと言うと、
読み取り専用とイミュータブルの違い
‥ということらしい。

ようするに、

kotlin
val list = listOf(0, 1, 2, 3, 4)
println(list)
//=> [0, 1, 2, 3, 4]

//MutableListにコピー(Shallow copy)して書き換えると
val mutableList = list as MutableList
mutableList[2] = 999

//listが書き換えられてる!!
println(list)
//=> [0, 1, 999, 3, 4]

ということ。(たぶん)

SwiftはDeep copyなので上記のようなことにはならない。

swift
let immutableArray = [0, 1, 2, 3, 4]
//immutableArray[2] = 999 //エラー
print(immutableArray)
//=> [0, 1, 2, 3, 4]

var mutableArray = immutableArray
mutableArray[2] = 999
print(mutableArray)
//=> [0, 1, 999, 3, 4] //こっちは当然書き換えられる
print(immutableArray)
//=> [0, 1, 2, 3, 4]   //元の方は書き換わっていない

mutable

val list = mutableListOf(0, 1, 2, 3, 4)
list[2] = 0
println(list)
//=> [0, 1, 0, 3, 4]

mapとか

val list = listOf(0, 3, 2, 4, 1)
println(list.map {it * 2})
//=> [0, 6, 4, 8, 2]
println(list.sorted())
//=> [0, 1, 2, 3, 4]

withIndex()

val ordinals = listOf<String>("first", "second", "third")
for ((index, value) in ordinals.withIndex()) {
    println("$index: $value")
}
//=> 0: first
//=> 1: second
//=> 2: third

辞書

val hashMap = hashMapOf("key" to "value")
println(hashMap["key"])
//=> value
println(hashMap.javaClass)
//=> class java.util.HashMap

lateinit

iOSのStoryboardの定番。

swift
class Hoge: UIViewController {
    @IBOutlet weak var button: UIButton!
}

こうやる。

kotlin
class Hoge : AppCompatActivity() {
    lateinit var button : Button
    override fun onCreate(savedInstanceState: Bundle?) {
    :
    button = findViewById(R.id.button) as Button
    }
}

Android

View取得

activity_main.xml
android:id="@+id/text_view"
val textView = findViewById(R.id.text_view) as TextView
println(textView.text)
//=> Hello World!

Kotlin Android Extensionsを使うとidで直接アクセス出来るようですが、あまりそういうのに依存するのもアレかと思うので使わないことにします。

println(text_view.text) //いきなり使える(らしい)
//=> Hello World!

リソース取得

String

strings.xml
<resources>
    <string name="string_hello">Hello Kotlin!</string>
</resources>
.kt
println(getString(R.string.string_hello))
//=> Hello Kotlin!

Color

API23未満がえらい面倒だったのでメモ。

colors.xml
<resources>
    <color name="red">#ff0000</color>
</resources>
.kt
ContextCompat.getColor(this, R.color.red)

API23以上はgetColor(R.color.red)で取れる。(たぶん)

Button

SAM (Single Abstract Method)

val button = findViewById(R.id.button) as Button
button.text = "push me"
button.setTextColor(BLUE)
//button.textColor = BLUE //これはダメだった
button.setOnClickListener { view ->
    val button = view as Button
    button.text = "thanks!"
}

SAM+引数省略

button.setOnClickListener {
    (it as Button).text = "thanks!"
}

関数化‥じゃなくて変数化?

val listener: (View) -> Unit = {
    (it as Button).text = "thanks!"
}
button.setOnClickListener(listener)

この辺はあとでちゃんと調べる。

遷移

普通に遷移

MainActivity.kt
//val intent = Intent(this@MainActivity, javaClass<SecondActivity>()) //エラー。古い書き方?
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)

this@MainActivityはクラスを明示せずthisだけでOK。

SecondActivity
finish()

戻る。

すげ替え

setContentView(R.layout.activity_second)

ListView

超基本的な部分だけ。
更新はadapterにお願いする。

val weekdays = mutableListOf(
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
)
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, weekdays)
val listView = findViewById(R.id.list_view) as ListView
listView.adapter = adapter

//更新
weekdays[1] = "HOGEHOGE"
adapter.notifyDataSetChanged()

//これでもいける(けどキャストが‥)
(listView.adapter as ArrayAdapter<*>).notifyDataSetChanged()

参考:[Android] ListView と ArrayAdapter 簡単なテキストリストの表示

Preference

取得

val pref = getSharedPreferences("Hoge", MODE_PRIVATE)

基本形。nameとmodeを指定して取得。modeのMODE_WORLD_READABLEMODE_WORLD_WRITEABLEはdeprecatedになっている。

val pref = getPreferences(MODE_PRIVATE)

アクティビティのクラス名で取得。例えば、nameに"MainActivity"を指定するのと同じこと。

val pref = PreferenceManager.getDefaultSharedPreferences(this)

パッケージ名で取得出来る。modeはMODE_PRIVATE固定。MODE_WORLD_READABLEMODE_WORLD_WRITEABLEが無くなっているので、これだけでいいんじゃないかと思う。

書き込み

pref.edit().putString("key", "hoge").commit()

Editorを通して書き込む。型は、int、long、float、boolean、String。
commit()は同期、apply()は非同期で書き込む。

読み込み

println(pref1.getString("key", "default"));
//=> hoge
println(pref1.getString("undefinedKey", "default"));
//=> default

第2引数でキーが未定義の場合の値を指定する。

xml

com.example.testpreference.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="key">hoge</string>
</map>

参考:SharedPreferencesに出力したデータの保存場所

時間差処理

とりあえずメインスレッド用。UI触りたいときに。

.kt
Handler(mainLooper).postDelayed({
    //処理
}, 3000) //3000ms後
fuzzball
つい出来心で。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away