Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlinで作るAndroidアプリ開発入門

 Kotlinで作るAndroidアプリ開発入門

【学生限定】Kotlinで作るAndroidアプリ開発入門 @ヤフー OthloEvent#38
https://othlotech.connpass.com/event/96786/

サンプルコード
https://github.com/mura/othloevent-android

Yohei Murayama

November 11, 2018
Tweet

More Decks by Yohei Murayama

Other Decks in Programming

Transcript

  1. その他のAndroidアプリの作り⽅ • Flutter (Dart) / Google • Xamarin.Android (C#) /

    Microsoft • React Native (JavaScript) / Facebook • Unity (C#) / Unity Technology
  2. MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?)

    { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val textView = findViewById<TextView>(R.id.textView) } } setContentView()でxmlから Viewのインスタンスを作成 findViewById()でレイアウトからほしいViewを探す
  3. Kotlinの型 // 変数名の後ろに型が書ける val count: Int = 0 // キャストしたいときは

    as を使う // キャストしたのでtextVewは⾃動でTextView型になる val textView = view as TextView
  4. コールバックの引数(クリックされたView) が返される Buttonのクリック val button = findViewById<Button>(R.id.button) button.setOnClickListener { view

    -> // クリックしたときに実⾏されるブロック } findViewById()で探し出すViewの型を指定 ブロック⾃体はコールバックのラムダ式
  5. クリックしたときの処理 val textView = findViewById<TextView>(R.id.textView) val button = findViewById<Button>(R.id.button) button.setOnClickListener

    { _ -> textView.text = "Yohei Murayama" } 使わない引数は _ で⽰す プロパティアクセスのように⾒えて実はsetText()を叩いてい
  6. MainActivity.kt val editText = findViewById<EditText>(R.id.editText) button.setOnClickListener { _ -> textView.text

    = editText.text } プロパティアクセスのように⾒えて実はgetText()を叩いている テキストボックスはEditTextクラス
  7. SharedPreferencesの使い⽅ val settings = getSharedPreferences("setting", Context.MODE_PRIVATE) val text = settings.getString("text",

    "") 設定を保存するファイル名 MODEは必ずPRIVATE 型ごとにgetメッドがある 設定を保存するキー名 値がなかったときの初期値
  8. Kotlinのフィールド // フィールドでは初期化が必要 var number: Int = 0 // 初期化しない=null許容であればクラス名のあとに?を付ける

    var number: Int? = null // あとで必ず初期化するから!というときはlateinit varを使う lateinit var number: Int // おまけ:遅延初期化をしたい場合は by lazy (valのみ) val number: Int by lazy { // 初期化処理を書く。ただし最初にアクセスした1回しか呼ばれない }
  9. 可視性 • フィールドやメンバメソッドはデフォルトで public • private はおなじクラスからしかアクセスできない • protected は

    private + ⼦クラス • internal は同じモジュールからアクセスできる • クラスやメソッドを継承は継承元に open がついたものしかできない ◦ Java的に⾔えばデフォルトは final 状態
  10. object 宣⾔ // object 宣⾔したものはそのものがインスタンスみたいなもの object DataProviderManager { fun registerDataProvider(provider:

    DataProvider) { // ... } val allDataProviders: Collection<DataProvider> get() = // ... } // JavaでもKotlinでもクラスメソッドのように呼べる DataProviderManager.registerDataProvider(...)
  11. object 式 // objectとよく似たものでobject式がある // こちらは無名クラスを作るもの window.addMouseListener(object : MouseAdapter() {

    override fun mouseClicked(e: MouseEvent) { // ... } override fun mouseEntered(e: MouseEvent) { // ... } })
  12. companion object class MyClass { // class 宣⾔の中に書く companion object

    { // メソッドやフィールドを定義できる val foo: String = "bar" fun create(): MyClass = MyClass() } } // 実体はクラス内にある1個のインスタンス(コンパニオンオブジェクト) val x = MyClass.Companion // コンパニオンオブジェクトは省略して書ける val instance = MyClass.create()
  13. textViewに値をset (初期値はお好みで) MainActivity.kt(1) class MainActivity : AppCompatActivity() { companion object

    { const val PREF_NAME = "settings" } private lateinit var settings: SharedPreferences override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) settings = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) val textView = findViewById<TextView>(R.id.textView) textView.text = settings.getString("text", "DEFAULT!") } companion objectを使って 定数を表現 onCreate()で初期化するの でlateinit var 忘れずに初期化する
  14. MainActivity.kt(2) button.setOnClickListener { _ -> val inputText = editText.text.toString() textView.text

    = inputText settings.edit() .putString("text", inputText) .apply() } EditText.textはEditableクラ スなのでStringに変換 Editorクラスを取得して書き込み準備 書き込む型に応じてメソッドを変える 最後にapply()を忘れずに!
  15. MainActivity.kt val secondButton = findViewById<Button>(R.id.secondButton) secondButton.setOnClickListener { val intent =

    Intent(this, SecondActivity::class.java) startActivity(intent) } Activityを呼び出すにはIntentクラスに呼び出したいクラスを渡す startActivity()メソッドでintentで指定したActivityを呼び出す
  16. Intent • 他のActivityやServiceなどAndroidの他のコンポーネントへの指⽰を格納する クラス • Action:指⽰を出したコンポーネントに何をしてほしいか ◦ 例:VIEW, EDIT, DIAL

    • Data:データの位置を⽰すUri • Flag:主にシステム向きの属性(スタックには載せないで、など) • Extras:コンポーネントにわたす追加データ
  17. MainActivity.kt secondButton.setOnClickListener { val intent = Intent(this, SecondActivity::class.java) intent.putExtra("name", "Yohei

    Murayama") startActivity(intent) } putExtra()を使ってデータを渡す オーバーロードされてるのでどの型で もputExtra()でOK
  18. SecondActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second) val nameTextView

    = findViewById<TextView>(R.id.nameTextView) val name: String? = intent.getStringExtra("name") nameTextView.text = name } Extraはnullを返すときがあるの で必ず?付きの型で受ける putExtra()と違い型別にメソッドが別れている TextView.textは仮にnullを⼊れても落ちない
  19. RecyclerViewに必要なクラス • RecyclerView ◦ リストを表⽰する場所 • RecyclerView.Adapter ◦ リストに表⽰するデータとRecyclerViewとの橋渡し •

    RecyclerView.ViewHolder ◦ リストに表⽰する要素のViewを保持している←リサイクルされるやつ • LayoutManager ◦ RecyclerViewに要素をどう並べるか決めるクラス(今回はLinearしか使わない)
  20. RecyclerViewの図式 RecyclerView ViewHolder ViewHolder ViewHolder ViewHolder ViewHolder ViewHolder LinearLayoutManager Adapter

    データのリスト 要素をどういうふうに並べるか を制御する 新しいViewHolderを作ったり 表⽰するViewHolderにデータをセットする
  21. <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="50dp" android:orientation="vertical" android:gravity="center">

    <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" tools:text="11⽉"/> </LinearLayout> layout_width, layout_heightは必須 ⼦要素の表⽰位置を決める のはgravity 初めて使うidは”@+id/”から始める Layout Editorで表⽰するときだけ出したい ⽂字は”tools:text”に⼊れる ⽂字サイズはsp サイズの単位はdp
  22. ListItemViewHolder.kt class ListItemViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { val name: TextView? =

    itemView.findViewById(R.id.name) } コンストラクタの引数 クラスのextendsやimplementsは :の後ろ継承元を書く 親クラスのコンストラクタへ渡す引数 nullを返す可能せいがあるので?付き コンスタクタの引数は フィールドの初期化で使⽤可能
  23. MonthRecyclerViewAdapter.kt class MonthRecycleViewAdapter(private val months: List<String>): RecyclerView.Adapter<ListItemViewHolder>() { override fun

    onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder { val itemView = LayoutInflater.from(parent.context) .inflate(R.layout.listitem, parent, false) return ListItemViewHolder(itemView) } override fun getItemCount(): Int { return months.size } override fun onBindViewHolder(holder: ListItemViewHolder, position: Int) { holder.name?.text = months[position] } }
  24. MonthRecyclerViewAdapter.onCreateViewHolder override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder { val

    itemView = LayoutInflater.from(parent.context) .inflate(R.layout.listitem, parent, false) return ListItemViewHolder(itemView) } いろいろな要素を表⽰するときにtypeを指定できる LayoutInflaterを使ってlistitem.xmlからViewを作る さきほど作ったViewHolderのインスタンスを返す
  25. MonthRecyclerViewAdapter.getItemCount class MonthRecycleViewAdapter(private val months: List<String>): RecyclerView.Adapter<ListItemViewHolder>() { override fun

    getItemCount(): Int { return months.size } 引数に可視性を書くとそのままフィールドになる リスト全体のサイズを返す
  26. MonthRecyclerViewAdapter.onBindViewHolder override fun onBindViewHolder(holder: ListItemViewHolder, position: Int) { holder.name?.text =

    months[position] } 表⽰しようとしているViewHolderと 何番⽬の要素かが渡される ?:は 変数がnullじゃないときに後ろのメソッ ドを実⾏する (nullのときは何もしない) Kotlinの仕様でListでも配列のようなアクセスが可能
  27. SecondActivity.kt val recyclerView = findViewById<RecyclerView>(R.id.recycler_view) // ⾼さが固定の場合はtrueのほうがパフォーマンスがよくなる recyclerView.setHasFixedSize(true) // 縦⽅向のみにレイアウトする

    recyclerView.layoutManager = LinearLayoutManager(this) // 表⽰するリストの作成 val months = listOf("1⽉","2⽉","3⽉","4⽉","5⽉","6⽉", "7⽉","8⽉","9⽉","10⽉","11⽉","12⽉") // AdapterをRecyclerViewにセット recyclerView.adapter = MonthRecyclerViewAdapter(months)
  28. SecondActivity.kt val recyclerView = findViewById<RecyclerView>(R.id.recycler_view) // ⾼さが固定の場合はtrueのほうがパフォーマンスがよくなる recyclerView.setHasFixedSize(true) // 縦⽅向のみにレイアウトする

    recyclerView.layoutManager = LinearLayoutManager(this) // 表⽰するリストの作成 val months = (1..12).map { "${it}⽉" } // AdapterをRecyclerViewにセット recyclerView.adapter = MonthRecyclerViewAdapter(months)
  29. SecondActivity.kt val recyclerView = findViewById<RecyclerView>(R.id.recycler_view) // ⾼さが固定の場合はtrueのほうがパフォーマンスがよくなる recyclerView.setHasFixedSize(true) // 縦⽅向のみにレイアウトする

    recyclerView.layoutManager = LinearLayoutManager(this) // 表⽰するリストの作成 val months = (2004..2018).flatMap { y -> (1..12).map { m -> "${y}年${m}⽉"} } // AdapterをRecyclerViewにセット recyclerView.adapter = MonthRecyclerViewAdapter(months)