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

2022 Android Training

2022 Android Training

22新卒技術研修で実施したAndroidアプリ開発研修の講義資料です。
動画も後日公開予定です。

ハンズオン用リポジトリ
https://github.com/mixigroup/AndroidTraining2022

B16717ef4b7aab0b253d933c3934f280?s=128

mixi_engineers

April 26, 2022
Tweet

More Decks by mixi_engineers

Other Decks in Programming

Transcript

  1. Android™研修 2022ver 2022/04/26 Android は Google LLC の商標です。

  2. 講師・チューター紹介 • 講師 ◦ 山田 淳登 (slack: atsuto.yamada) ◦ 2015新卒

    ◦ TIPSTAR Android版 開発リーダー • チューター ◦ 太田 祐樹 (slack: yuki.ota) ◦ 2021.09入社 2014高専卒 ◦ Androidは2018年頃からやっています
  3. 研修の目的と範囲 • 目的 ◦ 基礎的な部分の学習 ◦ Android開発の特徴・魅力が分かる • 範囲 ◦

    Androidの実行環境の概要 ◦ UIレイアウト ◦ リスト(RecyclerView) ◦ 非同期処理とKotlin Coroutine ◦ リアクティブストリーム( LiveData) ◦ MotionLayout ◦ ハンズオン(ストップウォッチを作ってみよう) ▪ 一緒にやるハンズオンと、自分で手を動かしてもらうハンズオンがある ※Kotlin文法は範囲外 10:31
  4. はじめに この研修の最終目標 ラップ機能付きストップウォッチを作る 10:32

  5. Androidアプリの基本構造① 10:32

  6. Androidネイティブアプリとは • Androidランタイム(ART)上で動くアプリ ◦ Java Virtual Machineではない ◦ Java APIが利用できる

    ◦ ただし独自実装のため、 Javaとは動作が異なるAPIも存在する • 開発言語は主にJava or Kotlin ◦ 今ではKotlinが主流 ◦ バイトコード(class)を吐き出すことができれば良い ▪ 例えばScalaでも開発可能 10:32
  7. JavaとKotlinの関係 • Java, Kotlin どちらもバイトコードを生成するための手段 • Kotlinでしか利用できない独自APIがある ◦ これが開発者がKotlinを選ぶ最大の理由 Java

    Kotlin バイトコード .class 実行可能形式 .dex パッケージ .apk ︙ 10:33
  8. 開発環境 • Android Studioと呼ばれるIDEを利用 ◦ IntelliJ IDEAベース 10:33

  9. ディレクトリ構成 • 初期状態では実際のディレクトリ構成で表示され ない • 左側のディレクトリツリーでProjectに切り替える と実際のディレクトリ構成になる • こちらの方が分かりやすいのでオススメ 10:34

  10. ディレクトリ構成 • app/src/main/res ◦ リソースを入れる場所 ▪ 画像、図形、UIレイアウト、テキスト など • app/src/main/java

    ◦ Java, Kotlinのコードを入れる場所 • app/build.gradle ◦ アプリのビルド時に必要な情報を記すファイル ▪ SDKバージョン ▪ 外部ライブラリ • app/src/main/AndroidManifest.xml ◦ アプリの構成情報を記すファイル 10:34
  11. リソースディレクトリ • app/src/main/res ◦ values/strings.xml ▪ アプリ内のUIで表示する文字列を定義する ▪ Java, Kotlinコード上に表示文字列を書くことはほぼ無い

    • 実行環境の言語設定によって内容を変えるため ◦ values/colors.xml ▪ アプリで利用する色コードを定義する ◦ values/themes.xml ▪ UIパーツの見た目の変更を定義する 10:35
  12. app/build.gradle • ビルド時に必要な情報が定義されている • アプリのバージョン • compileSdk ◦ どのAndroid SDKバージョンでビルドするか

    ◦ 32 = Android 12 • minSdk ◦ 動作可能な最低のAndroidバージョン • パッケージ名(applicationId) ◦ アプリを特定するための ID • 外部依存ライブラリ(dependencies) 10:35
  13. AndroidManifest.xml • アプリの構成情報 • アプリにどんな画面があるのか(Activity) • アプリにどんなサービスがあるのか(Service) ◦ サービスとは? ▪

    画面を持たないバックグラウンド処理を行うもの ▪ 消費電力節約の観点から、近年多用はされない ▪ プッシュ通知で使われる • アプリ名 • アプリアイコン • 外部アプリから自分のアプリ画面への呼び出し方法の定義(IntentFilter) ◦ 例:別アプリで「共有」を押すと、データを受け取りつつ自分のアプリを開く 10:36
  14. Androidアプリの基本構造② 10:36

  15. Activity • Androidでは1枚の画面をActivityという機能を利用して実装する ◦ AppCompatActivity:Androidバージョン間の互換性を維持するためのクラス • 画面内で行う処理は、Activityを起点に処理が伸びていく • 画面ごとにAppCompatActivityを継承したクラスを作成する 10:37

  16. Activityのライフサイクル • ライフサイクルとは ◦ 画面のステートによって呼ばれるメソッドと、その順序 • 画面のステート ◦ ステートの例:画面を開く、画面を起動したまま別アプリを開く、画 面を閉じる

    • onCreateで画面の初期化を行う • onDestroyで画面の終了処理を行う 画面の起動 onCreate onStart onResume 画面の表示 onPause onStop onDestroy 画面の終了 画面が見えな くなる 10:37
  17. ハンズオン①:サンプルプロジェクトの起動 • サンプルプロジェクトを起動してみる • プロジェクトをCloneする。以下をターミナルで実行 cd ~ mkdir AndroidStudioProjects cd

    AndroidStudioProjects git clone git@github.com:mixigroup/AndroidTraining2022.git cd AndroidTraining2022 git checkout lesson1 10:50
  18. ハンズオン①:サンプルプロジェクトの起動 • AndroidStudioを起動 • Openをクリック 10:50

  19. ハンズオン①:サンプルプロジェクトの起動 • 先程Cloneしたディレクトリを選択し、Openをクリック • 「Trust Gradle Project?」と出たら、Trust Projectをクリック 10:50

  20. ハンズオン①:サンプルプロジェクトの起動 • アプリをエミュレーター上で実行する 10:50

  21. 11:15まで休憩時間 11:15

  22. UIレイアウト 11:15

  23. View • Viewとは:画面上に何かを表示するためのコンポーネント • Viewを継承したさまざまなクラスがSDKで用意されている • 代表的なView ◦ TextView:文字列を表示 ◦

    ImageView:画像を表示 ◦ Button:ボタンを表示 ◦ EditText:文字列入力フォームを表示 • 画面で必要なViewをXMLで記述する(レイアウトXML) 11:16
  24. レイアウトXMLとActivity(Kotlinコード)の関係 • Viewを利用するにはインスタンスが必要 • レイアウトXMLをViewインスタンスに変換することでプログラム上で利用可能となる • レイアウトXMLはViewインスタンスを用意するための手段 ◦ レイアウトに限らず、 AndroidでのXML定義要素はすべてインスタンス化して利用する

    • レイアウトXMLをインスタンス化する機能はLayoutInflaterが提供 • 1つのXMLに存在するViewをまとめるためのHolderとしてViewBindingが利用され る • ActivityにsetContentViewすることで、その画面のUIとして利用される XML View View View View View ViewBinding 11:17
  25. TextView • 文字列を表示するためのView • XML属性を変更することで書式の変更が可能 ◦ android:id Viewを特定するためのID ◦ style 別途定義した属性を引っ張ってくる ◦

    android:text 表示するテキスト内容 ◦ android:textColor テキスト色 ◦ android:textSize テキストサイズ • リソースとして定義した値は @.../ で参照 ◦ @color/ ◦ @string/ 11:18
  26. Button • ボタンを表示するためのView • TextViewのサブクラスなので、TextViewの属性と共通 11:18

  27. サイズ単位 sp, dp • 世の中のAndroid端末のディスプレイは、高解像度・低解像度が混在している • よって、pixel単位をそのまま利用できない ◦ 低解像度ディスプレイでは大きく、高解像度ディスプレイでは小さく表示される •

    サイズ指定は dp を使う ◦ 画面のピクセル密度を考慮したサイズ指定が可能 • テキストサイズ指定では sp を使う ◦ 画面のピクセル密度に加え、 OSのフォントサイズ設定によって変化する単位 ◦ フォントサイズ標準時、 14sp = 14dp 11:19
  28. ViewGroupとは • ViewGroupとは:Viewを複数並べるためのコンポーネント • 代表的なViewGroup ◦ FrameLayout:重ねて表示 ◦ LinearLayout:縦方向や横方向に並べて表示 ◦

    ConstraintLayout:View同士の制約(並べ方)を定義して表示 ◦ ScrollView:表示領域をはみ出るくらいの大きな Viewをスクロール可能にする ◦ RecyclerView:スクロール可能な表示領域のみ Viewを配置する • これも同じくレイアウトXMLに記述する 11:20
  29. LinearLayout • 縦方向や横方向に並べて表示する • android:orientation ◦ vertical 縦に並べる ◦ horizontal 横に並べる 11:21

  30. ConstraintLayout • View同士の制約を設定して並べる start(左側面)を親の左側面にくっつける top(上側面)を親の上側面にくっつける start(左側面)をTEXT_1の右側面にくっつける top(上側面)をTEXT_1の下側面にくっつける 11:21

  31. ViewGroupに対しての属性指定 • ViewGroupに属しているViewは、親に対してどのよ うなサイズ・位置にするかを指定できる ◦ layout_…がついている属性は親に対する指定 • android:layout_width, android:layout_height ◦

    wrap_content Viewのコンテンツが収まるように ◦ match_parent 親要素の大きさに合わせる • android:layout_margin… ◦ マージンを取って位置を決定する 11:22
  32. ConstraintLayout Chain • ConstraintLayoutにおいて、お互いに依存し合った制約が設定されている場 合、うまくセンタリングされる • その際の並べ方を指定できる • android:layout_constraint(Horizontal/Vertical)_chainStyle ◦

    packed ◦ spread ◦ spread_inside packed spread spread_inside 11:23
  33. ConstraintLayout Chainの作り方(エディタ上) • (実際に解説 ブランチ名:example1) • Designを開きComponent Treeから複数のViewを選び、右クリックで作成 11:30

  34. ハンズオン②:【課題】秒数表示・ボタンを置く • ブランチ lesson2 をcheckout • 課題 ◦ MainActivityに紐付いているactivity_main.xmlを編集 ◦

    右のようにTextViewとButtonを配置する ◦ (必要なパラメーターは次ページ) • 時間:10分間(11:47まで) 11:47
  35. ハンズオン②:【課題】秒数表示・ボタンを置く マージン36dp マージン36dp 均等 均等 11:45

  36. ハンズオン②:正解解説 • (実際に解説 ブランチ名:lesson2-answer) 11:45

  37. ActivityからViewを操作する 12:00

  38. ActivityにViewを設定する • XMLで定義したViewは binding に格納され ている • activity_main.xml → ActivityMainBinding

    • setContentViewでActivityの画面として設 定する 12:01
  39. ActivityからViewを操作する • id: time_text → timeText • binding内にインスタンスがあるので、その プロパティをコード側で変更できる 12:02

  40. 任意のタイミングでViewを操作する • setOnClickListenerを使うことで、Viewが クリックされた時に動作させることができ る 12:03

  41. リストの表示 12:03

  42. なぜRecyclerViewを使うのか • リスト表示ではRecyclerViewの利用が必須 • LinearLayoutを使ってリストを作成するとアイテ ムが多数あった場合、描画する必要の無い領 域までViewがレイアウトされる ◦ リストの要素が100個あればTextViewが100個必要に なる

    ◦ 見えている領域は十数個だけ。十数個しか使わないの に無駄 ︙ 画面領域が赤線部分だとすると この領域外のTextViewが無駄 12:04
  43. なぜRecyclerViewを使うのか • RecyclerViewを使うと、表示領域分だけViewを レイアウトできる • スクロールすると必要に応じてViewが新規作成・ 再利用される 12:05

  44. なぜRecyclerViewを使うのか • スクロールすると、領域外に出たViewがリサイク ルされる • リサイクルされたViewは次に見えるアイテムとし てレイアウトされる 12:05

  45. RecyclerViewを使う • リスト内の1アイテム分のレイアウトXMLを新規作成する • 表示箇所にRecyclerViewを配置 • app:layoutManager ◦ 並べ方を設定 ◦

    androidx.recyclerview.widget.LinearLayoutManager ▪ LinearLayoutのように縦方向に並べる 12:06
  46. RecyclerViewを使う • RecyclerView.Adapterを実装する ◦ リストにあるデータをViewに変換する • ハンズオンではこの実装である ListAdapter を 利用

    • onCreateViewHolder ◦ ViewHolderを返す ▪ アイテム内で使うViewを保持するクラス ▪ 歴史的にはViewBindingが後発 • onBindViewHolder ◦ positionに位置するデータを Viewに設定する 12:06
  47. ハンズオン③:リスト表示する • 一緒にやるハンズオン • ブランチ lesson3 をcheckout • 解説 ◦

    ボタンを押すとリストにアイテムが追加される実装 ◦ Adapterの実装 ◦ MainActivity側の実装 12:15
  48. 昼休憩:13:30まで 13:30

  49. 非同期処理 13:30

  50. Androidにおける非同期処理 • Androidにおける処理スレッドの種類 ◦ Mainスレッド(UIスレッド) ◦ IOスレッド(バックグラウンドスレッド) • onCreateなどのフレームワークからのコールバックはMainスレッドで呼ばれる •

    Mainスレッドで重い処理やネットワーク通信を行うと ◦ 処理(通信)が終わるまでアプリが固まる ◦ ネットワーク通信はフレームワークの制約によりそもそもできない(クラッシュする) • Viewの操作はMainスレッドで行う必要がある ◦ IOスレッド→Mainスレッドへのコールバックが必要 13:30
  51. Kotlin Corouines • 同一ブロック内で中断可能なスコープ ◦ →CoroutineScope ◦ Activityに連動したCorouineScopeは lifecycleScope.launch で生成

    • 通常 Thread.sleep を使うとスレッドが停止す る • delay を使うとスレッドが停止せず、別ブロック にある処理を続行する • 実行スレッドを同一ブロック内で変更可能
  52. Kotlin Corouines • 処理が不要になったら適切にCoroutineScopeが終了される ◦ アプリが終了すれば停止する • while無限ループもガシガシ使える 13:33

  53. Kotlin Corouines • withContextを利用することで、そのブロックだけ別のスレッドで実行が可能 • (無駄ではあるが)インクリメントだけIOスレッドで実行している ◦ Dispatcher.MainでMainスレッドでの実行も指定できる。 13:35

  54. ViewModelとLiveData 13:36

  55. 責務の分離 • 画面に機能を実装していくとActivityの肥大化する ◦ 可読性の低下 ◦ メンテナンスコストの増加 ◦ バグの増加 •

    各クラスが特定の処理に集中できる設計が重要 ◦ →ViewModelの登場 13:37 Activity ViewModel ViewModelが用意した データをViewに設定す ることに集中 UI表示するデータを用意 することに集中 データ
  56. ViewModel • AndroidViewModel を継承したクラスを用意 • by viewModels<Type>() ◦ Activity内でのViewModel生成 13:38

  57. LiveData • ViewModelがActivityに依存することは許されない ◦ インスタンスの生存期間が異なる・責務分離の明確化 などの理由 • ViewModelからActivityにデータを伝える方法が必要 ◦ →LiveDataを使う

    • LiveData:データの入れ物 • 更新を通知する機能が備わっている • LiveData.observe ◦ データの変化時に実行されるリスナーを設定する 13:39
  58. LiveDataの仲間たち • MutableLiveData ◦ 外部から自由に変更可能な LiveData ◦ setValue(Kotlin上からは value と省略)でデータを設定

    • MediatorLiveData ◦ 別のLiveData(ソース)を元にデータ設定できる LiveData ◦ addSource ▪ 別のLiveDataソースを設定 ▪ ソースの値変更されたら、ブロックが呼ばれる 13:40
  59. MediatorLiveDataのショートカットたち • LiveData.map { } ◦ 他のLiveDataの値を変換する 13:41

  60. MediatorLiveDataのショートカットたち • LiveData.switchMap { } ◦ 他のLiveDataの値が変化したら、参照する LiveDataを切り替える ◦ ※liveData

    { } ブロックは次に紹介 13:42
  61. Coroutine LiveData(liveData{ }) • ActivityがObserveしている間だけ動 作するCoroutineScopeを生成 • ブロック内でデータを生成し、emit() することで値を更新する 13:45

  62. ハンズオン④:LiveDataでステートを管理する • 一緒にやるハンズオン • ブランチ lesson4 をcheckout • ViewModelにあるLiveDataでストップウォッチのステート を管理する

    • ステートを元に右側のボタンの以下を変更 ◦ テキスト ◦ 色 ◦ クリックアクション 14:05
  63. ハンズオン⑤:ストップウォッチの秒数を表示する • ブランチ lesson5 をcheckout • 課題 ◦ MainViewModel.currentTimeを元に、currentTimeTextの中身を 実装

    ◦ currentTimeTextをTextViewに表示 • 時間:20分間(14:33まで) 14:33
  64. ハンズオン⑤:ストップウォッチの秒数を表示する • (解説 ブランチ名:lesson5-answer) 14:35

  65. 14:50まで(10分)休憩

  66. MotionLayout 14:50

  67. MotionLayout • Viewを移動させるコンポーネント(ViewGroup) • ConstraintLayoutのサブクラス • 開始状態と終了状態の制約を定義、その間をアニメーションさせる ◦ レイアウトXMLとは別に、MotionSceneというXMLを用意する 14:50

  68. MotionLayout TextView(time_text)を移動させる例 親要素 ConstraintLayoutをMotionLayoutに変更 app:layoutDescriptionを追加 MotionSceneが定義されたxmlを指定 動かしたいViewの制約を削除 14:51

  69. MotionLayout Transitionに開始・終了ステートと、遷移時間 を設定 Constraintで開始ステートにおける制約を設 定 Constraintに終了ステートにおける制約を設 定 14:52

  70. MotionLayout • transitionToEnd() ◦ 終了ステートに遷移 • transitionToStart() ◦ 開始ステートに遷移 14:53

  71. ハンズオン⑥:MotionLayoutを使ってViewを移動させる • 一緒にやるハンズオン • ブランチ lesson6 をcheckout • ラップボタンを押すと、time_text を上に上げ

    つつ、recycler_view_header, recycler_view が見えるようにする 15:10
  72. ハンズオン⑦:最終課題 • ブランチ lesson7 をcheckout • 1時間(16:15まで) • ラップ機能を完成させる ◦

    ストップウォッチ開始中だけ、ラップボタンを有効にする (Button.isEnabled) ◦ ラップ時間表示を実装する ◦ ラップがあるときは時間表示を上げる ◦ ラップがないときは時間表示を下げる • 完成したら、別ブランチで差分をpushし、lesson7 へのPRを作成 16:10