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ではないかと言うと、
読み取り専用とイミュータブルの違い
‥ということらしい。
ようするに、
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なので上記のようなことにはならない。
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の定番。
class Hoge: UIViewController {
@IBOutlet weak var button: UIButton!
}
こうやる。
class Hoge : AppCompatActivity() {
lateinit var button : Button
override fun onCreate(savedInstanceState: Bundle?) {
:
button = findViewById(R.id.button) as Button
}
}
Android
View取得
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
<resources>
<string name="string_hello">Hello Kotlin!</string>
</resources>
println(getString(R.string.string_hello))
//=> Hello Kotlin!
Color
API23未満がえらい面倒だったのでメモ。
<resources>
<color name="red">#ff0000</color>
</resources>
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)
この辺はあとでちゃんと調べる。
遷移
普通に遷移
//val intent = Intent(this@MainActivity, javaClass<SecondActivity>()) //エラー。古い書き方?
val intent = Intent(this@MainActivity, SecondActivity::class.java)
startActivity(intent)
this@MainActivity
はクラスを明示せずthis
だけでOK。
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_READABLE
やMODE_WORLD_WRITEABLE
はdeprecatedになっている。
val pref = getPreferences(MODE_PRIVATE)
アクティビティのクラス名で取得。例えば、nameに"MainActivity"を指定するのと同じこと。
val pref = PreferenceManager.getDefaultSharedPreferences(this)
パッケージ名で取得出来る。modeはMODE_PRIVATE
固定。MODE_WORLD_READABLE
やMODE_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
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="key">hoge</string>
</map>
参考:SharedPreferencesに出力したデータの保存場所
時間差処理
とりあえずメインスレッド用。UI触りたいときに。
Handler(mainLooper).postDelayed({
//処理
}, 3000) //3000ms後