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

Androidアプリ開発研修【ミクシィ22新卒技術研修】

 Androidアプリ開発研修【ミクシィ22新卒技術研修】

22新卒技術研修で実施したAndroidアプリ開発研修の講義資料です。
動画:https://youtu.be/tqCDiQygR70

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

MIXI ENGINEERS
PRO

April 26, 2022
Tweet

More Decks by MIXI ENGINEERS

Other Decks in Programming

Transcript

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

    View Slide

  2. 講師・チューター紹介
    ● 講師
    ○ 山田 淳登 (slack: atsuto.yamada)
    ○ 2015新卒
    ○ TIPSTAR Android版 開発リーダー
    ● チューター
    ○ 太田 祐樹 (slack: yuki.ota)
    ○ 2021.09入社 2014高専卒
    ○ Androidは2018年頃からやっています

    View Slide

  3. 研修の目的と範囲
    ● 目的
    ○ 基礎的な部分の学習
    ○ Android開発の特徴・魅力が分かる
    ● 範囲
    ○ Androidの実行環境の概要
    ○ UIレイアウト
    ○ リスト(RecyclerView)
    ○ 非同期処理とKotlin Coroutine
    ○ リアクティブストリーム( LiveData)
    ○ MotionLayout
    ○ ハンズオン(ストップウォッチを作ってみよう)
    ■ 一緒にやるハンズオンと、自分で手を動かしてもらうハンズオンがある
    ※Kotlin文法は範囲外
    10:31

    View Slide

  4. はじめに
    この研修の最終目標
    ラップ機能付きストップウォッチを作る
    10:32

    View Slide

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

    View Slide

  6. Androidネイティブアプリとは
    ● Androidランタイム(ART)上で動くアプリ
    ○ Java Virtual Machineではない
    ○ Java APIが利用できる
    ○ ただし独自実装のため、 Javaとは動作が異なるAPIも存在する
    ● 開発言語は主にJava or Kotlin
    ○ 今ではKotlinが主流
    ○ バイトコード(class)を吐き出すことができれば良い
    ■ 例えばScalaでも開発可能
    10:32

    View Slide

  7. JavaとKotlinの関係
    ● Java, Kotlin どちらもバイトコードを生成するための手段
    ● Kotlinでしか利用できない独自APIがある
    ○ これが開発者がKotlinを選ぶ最大の理由
    Java
    Kotlin
    バイトコード
    .class
    実行可能形式
    .dex
    パッケージ
    .apk

    10:33

    View Slide

  8. 開発環境
    ● Android Studioと呼ばれるIDEを利用
    ○ IntelliJ IDEAベース
    10:33

    View Slide

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

    View Slide

  10. ディレクトリ構成
    ● app/src/main/res
    ○ リソースを入れる場所
    ■ 画像、図形、UIレイアウト、テキスト など
    ● app/src/main/java
    ○ Java, Kotlinのコードを入れる場所
    ● app/build.gradle
    ○ アプリのビルド時に必要な情報を記すファイル
    ■ SDKバージョン
    ■ 外部ライブラリ
    ● app/src/main/AndroidManifest.xml
    ○ アプリの構成情報を記すファイル
    10:34

    View Slide

  11. リソースディレクトリ
    ● app/src/main/res
    ○ values/strings.xml
    ■ アプリ内のUIで表示する文字列を定義する
    ■ Java, Kotlinコード上に表示文字列を書くことはほぼ無い
    ● 実行環境の言語設定によって内容を変えるため
    ○ values/colors.xml
    ■ アプリで利用する色コードを定義する
    ○ values/themes.xml
    ■ UIパーツの見た目の変更を定義する
    10:35

    View Slide

  12. app/build.gradle
    ● ビルド時に必要な情報が定義されている
    ● アプリのバージョン
    ● compileSdk
    ○ どのAndroid SDKバージョンでビルドするか
    ○ 32 = Android 12
    ● minSdk
    ○ 動作可能な最低のAndroidバージョン
    ● パッケージ名(applicationId)
    ○ アプリを特定するための ID
    ● 外部依存ライブラリ(dependencies)
    10:35

    View Slide

  13. AndroidManifest.xml
    ● アプリの構成情報
    ● アプリにどんな画面があるのか(Activity)
    ● アプリにどんなサービスがあるのか(Service)
    ○ サービスとは?
    ■ 画面を持たないバックグラウンド処理を行うもの
    ■ 消費電力節約の観点から、近年多用はされない
    ■ プッシュ通知で使われる
    ● アプリ名
    ● アプリアイコン
    ● 外部アプリから自分のアプリ画面への呼び出し方法の定義(IntentFilter)
    ○ 例:別アプリで「共有」を押すと、データを受け取りつつ自分のアプリを開く
    10:36

    View Slide

  14. Androidアプリの基本構造②
    10:36

    View Slide

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

    View Slide

  16. Activityのライフサイクル
    ● ライフサイクルとは
    ○ 画面のステートによって呼ばれるメソッドと、その順序
    ● 画面のステート
    ○ ステートの例:画面を開く、画面を起動したまま別アプリを開く、画
    面を閉じる
    ● onCreateで画面の初期化を行う
    ● onDestroyで画面の終了処理を行う
    画面の起動
    onCreate
    onStart
    onResume
    画面の表示
    onPause
    onStop
    onDestroy
    画面の終了
    画面が見えな
    くなる
    10:37

    View Slide

  17. ハンズオン①:サンプルプロジェクトの起動
    ● サンプルプロジェクトを起動してみる
    ● プロジェクトをCloneする。以下をターミナルで実行
    cd ~
    mkdir AndroidStudioProjects
    cd AndroidStudioProjects
    git clone
    [email protected]:mixigroup/AndroidTraining2022.git
    cd AndroidTraining2022
    git checkout lesson1
    10:50

    View Slide

  18. ハンズオン①:サンプルプロジェクトの起動
    ● AndroidStudioを起動
    ● Openをクリック
    10:50

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. UIレイアウト
    11:15

    View Slide

  23. View
    ● Viewとは:画面上に何かを表示するためのコンポーネント
    ● Viewを継承したさまざまなクラスがSDKで用意されている
    ● 代表的なView
    ○ TextView:文字列を表示
    ○ ImageView:画像を表示
    ○ Button:ボタンを表示
    ○ EditText:文字列入力フォームを表示
    ● 画面で必要なViewをXMLで記述する(レイアウトXML)
    11:16

    View Slide

  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

    View Slide

  25. TextView
    ● 文字列を表示するためのView
    ● XML属性を変更することで書式の変更が可能
    ○ android:id Viewを特定するためのID
    ○ style 別途定義した属性を引っ張ってくる
    ○ android:text 表示するテキスト内容
    ○ android:textColor テキスト色
    ○ android:textSize テキストサイズ
    ● リソースとして定義した値は @.../ で参照
    ○ @color/
    ○ @string/
    11:18

    View Slide

  26. Button
    ● ボタンを表示するためのView
    ● TextViewのサブクラスなので、TextViewの属性と共通
    11:18

    View Slide

  27. サイズ単位 sp, dp
    ● 世の中のAndroid端末のディスプレイは、高解像度・低解像度が混在している
    ● よって、pixel単位をそのまま利用できない
    ○ 低解像度ディスプレイでは大きく、高解像度ディスプレイでは小さく表示される
    ● サイズ指定は dp を使う
    ○ 画面のピクセル密度を考慮したサイズ指定が可能
    ● テキストサイズ指定では sp を使う
    ○ 画面のピクセル密度に加え、 OSのフォントサイズ設定によって変化する単位
    ○ フォントサイズ標準時、 14sp = 14dp
    11:19

    View Slide

  28. ViewGroupとは
    ● ViewGroupとは:Viewを複数並べるためのコンポーネント
    ● 代表的なViewGroup
    ○ FrameLayout:重ねて表示
    ○ LinearLayout:縦方向や横方向に並べて表示
    ○ ConstraintLayout:View同士の制約(並べ方)を定義して表示
    ○ ScrollView:表示領域をはみ出るくらいの大きな Viewをスクロール可能にする
    ○ RecyclerView:スクロール可能な表示領域のみ Viewを配置する
    ● これも同じくレイアウトXMLに記述する
    11:20

    View Slide

  29. LinearLayout
    ● 縦方向や横方向に並べて表示する
    ● android:orientation
    ○ vertical 縦に並べる
    ○ horizontal 横に並べる
    11:21

    View Slide

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

    View Slide

  31. ViewGroupに対しての属性指定
    ● ViewGroupに属しているViewは、親に対してどのよ
    うなサイズ・位置にするかを指定できる
    ○ layout_…がついている属性は親に対する指定
    ● android:layout_width, android:layout_height
    ○ wrap_content Viewのコンテンツが収まるように
    ○ match_parent 親要素の大きさに合わせる
    ● android:layout_margin…
    ○ マージンを取って位置を決定する
    11:22

    View Slide

  32. ConstraintLayout Chain
    ● ConstraintLayoutにおいて、お互いに依存し合った制約が設定されている場
    合、うまくセンタリングされる
    ● その際の並べ方を指定できる
    ● android:layout_constraint(Horizontal/Vertical)_chainStyle
    ○ packed
    ○ spread
    ○ spread_inside
    packed spread spread_inside
    11:23

    View Slide

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

    View Slide

  34. ハンズオン②:【課題】秒数表示・ボタンを置く
    ● ブランチ lesson2 をcheckout
    ● 課題
    ○ MainActivityに紐付いているactivity_main.xmlを編集
    ○ 右のようにTextViewとButtonを配置する
    ○ (必要なパラメーターは次ページ)
    ● 時間:10分間(11:47まで)
    11:47

    View Slide

  35. ハンズオン②:【課題】秒数表示・ボタンを置く
    マージン36dp
    マージン36dp
    均等
    均等
    11:45

    View Slide

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

    View Slide

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

    View Slide

  38. ActivityにViewを設定する
    ● XMLで定義したViewは binding に格納され
    ている
    ● activity_main.xml → ActivityMainBinding
    ● setContentViewでActivityの画面として設
    定する
    12:01

    View Slide

  39. ActivityからViewを操作する
    ● id: time_text → timeText
    ● binding内にインスタンスがあるので、その
    プロパティをコード側で変更できる
    12:02

    View Slide

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

    12:03

    View Slide

  41. リストの表示
    12:03

    View Slide

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

    画面領域が赤線部分だとすると
    この領域外のTextViewが無駄
    12:04

    View Slide

  43. なぜRecyclerViewを使うのか
    ● RecyclerViewを使うと、表示領域分だけViewを
    レイアウトできる
    ● スクロールすると必要に応じてViewが新規作成・
    再利用される
    12:05

    View Slide

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

    View Slide

  45. RecyclerViewを使う
    ● リスト内の1アイテム分のレイアウトXMLを新規作成する
    ● 表示箇所にRecyclerViewを配置
    ● app:layoutManager
    ○ 並べ方を設定
    ○ androidx.recyclerview.widget.LinearLayoutManager
    ■ LinearLayoutのように縦方向に並べる
    12:06

    View Slide

  46. RecyclerViewを使う
    ● RecyclerView.Adapterを実装する
    ○ リストにあるデータをViewに変換する
    ● ハンズオンではこの実装である ListAdapter を
    利用
    ● onCreateViewHolder
    ○ ViewHolderを返す
    ■ アイテム内で使うViewを保持するクラス
    ■ 歴史的にはViewBindingが後発
    ● onBindViewHolder
    ○ positionに位置するデータを Viewに設定する
    12:06

    View Slide

  47. ハンズオン③:リスト表示する
    ● 一緒にやるハンズオン
    ● ブランチ lesson3 をcheckout
    ● 解説
    ○ ボタンを押すとリストにアイテムが追加される実装
    ○ Adapterの実装
    ○ MainActivity側の実装
    12:15

    View Slide

  48. 昼休憩:13:30まで
    13:30

    View Slide

  49. 非同期処理
    13:30

    View Slide

  50. Androidにおける非同期処理
    ● Androidにおける処理スレッドの種類
    ○ Mainスレッド(UIスレッド)
    ○ IOスレッド(バックグラウンドスレッド)
    ● onCreateなどのフレームワークからのコールバックはMainスレッドで呼ばれる
    ● Mainスレッドで重い処理やネットワーク通信を行うと
    ○ 処理(通信)が終わるまでアプリが固まる
    ○ ネットワーク通信はフレームワークの制約によりそもそもできない(クラッシュする)
    ● Viewの操作はMainスレッドで行う必要がある
    ○ IOスレッド→Mainスレッドへのコールバックが必要
    13:30

    View Slide

  51. Kotlin Corouines
    ● 同一ブロック内で中断可能なスコープ
    ○ →CoroutineScope
    ○ Activityに連動したCorouineScopeは
    lifecycleScope.launch で生成
    ● 通常 Thread.sleep を使うとスレッドが停止す

    ● delay を使うとスレッドが停止せず、別ブロック
    にある処理を続行する
    ● 実行スレッドを同一ブロック内で変更可能

    View Slide

  52. Kotlin Corouines
    ● 処理が不要になったら適切にCoroutineScopeが終了される
    ○ アプリが終了すれば停止する
    ● while無限ループもガシガシ使える
    13:33

    View Slide

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

    View Slide

  54. ViewModelとLiveData
    13:36

    View Slide

  55. 責務の分離
    ● 画面に機能を実装していくとActivityの肥大化する
    ○ 可読性の低下
    ○ メンテナンスコストの増加
    ○ バグの増加
    ● 各クラスが特定の処理に集中できる設計が重要
    ○ →ViewModelの登場
    13:37
    Activity ViewModel
    ViewModelが用意した
    データをViewに設定す
    ることに集中
    UI表示するデータを用意
    することに集中
    データ

    View Slide

  56. ViewModel
    ● AndroidViewModel を継承したクラスを用意
    ● by viewModels()
    ○ Activity内でのViewModel生成
    13:38

    View Slide

  57. LiveData
    ● ViewModelがActivityに依存することは許されない
    ○ インスタンスの生存期間が異なる・責務分離の明確化 などの理由
    ● ViewModelからActivityにデータを伝える方法が必要
    ○ →LiveDataを使う
    ● LiveData:データの入れ物
    ● 更新を通知する機能が備わっている
    ● LiveData.observe
    ○ データの変化時に実行されるリスナーを設定する
    13:39

    View Slide

  58. LiveDataの仲間たち
    ● MutableLiveData
    ○ 外部から自由に変更可能な LiveData
    ○ setValue(Kotlin上からは value と省略)でデータを設定
    ● MediatorLiveData
    ○ 別のLiveData(ソース)を元にデータ設定できる LiveData
    ○ addSource
    ■ 別のLiveDataソースを設定
    ■ ソースの値変更されたら、ブロックが呼ばれる
    13:40

    View Slide

  59. MediatorLiveDataのショートカットたち
    ● LiveData.map { }
    ○ 他のLiveDataの値を変換する
    13:41

    View Slide

  60. MediatorLiveDataのショートカットたち
    ● LiveData.switchMap { }
    ○ 他のLiveDataの値が変化したら、参照する LiveDataを切り替える
    ○ ※liveData { } ブロックは次に紹介
    13:42

    View Slide

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

    View Slide

  62. ハンズオン④:LiveDataでステートを管理する
    ● 一緒にやるハンズオン
    ● ブランチ lesson4 をcheckout
    ● ViewModelにあるLiveDataでストップウォッチのステート
    を管理する
    ● ステートを元に右側のボタンの以下を変更
    ○ テキスト
    ○ 色
    ○ クリックアクション
    14:05

    View Slide

  63. ハンズオン⑤:ストップウォッチの秒数を表示する
    ● ブランチ lesson5 をcheckout
    ● 課題
    ○ MainViewModel.currentTimeを元に、currentTimeTextの中身を
    実装
    ○ currentTimeTextをTextViewに表示
    ● 時間:20分間(14:33まで)
    14:33

    View Slide

  64. ハンズオン⑤:ストップウォッチの秒数を表示する
    ● (解説 ブランチ名:lesson5-answer)
    14:35

    View Slide

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

    View Slide

  66. MotionLayout
    14:50

    View Slide

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

    View Slide

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

    View Slide

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

    Constraintに終了ステートにおける制約を設

    14:52

    View Slide

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

    View Slide

  71. ハンズオン⑥:MotionLayoutを使ってViewを移動させる
    ● 一緒にやるハンズオン
    ● ブランチ lesson6 をcheckout
    ● ラップボタンを押すと、time_text を上に上げ
    つつ、recycler_view_header, recycler_view
    が見えるようにする
    15:10

    View Slide

  72. ハンズオン⑦:最終課題
    ● ブランチ lesson7 をcheckout
    ● 1時間(16:15まで)
    ● ラップ機能を完成させる
    ○ ストップウォッチ開始中だけ、ラップボタンを有効にする
    (Button.isEnabled)
    ○ ラップ時間表示を実装する
    ○ ラップがあるときは時間表示を上げる
    ○ ラップがないときは時間表示を下げる
    ● 完成したら、別ブランチで差分をpushし、lesson7
    へのPRを作成
    16:10

    View Slide