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

Android研修【MIXI 24新卒技術研修】

Android研修【MIXI 24新卒技術研修】

本スライドは、MIXIの2024年度新卒向け技術研修で使用された資料です。

<科目名>
Android研修

<関連リンク>
動画▶ https://youtu.be/8bQnUEDPg3Q
リポジトリ▶ https://github.com/mixigroup/2024AndroidTraining

※お願い※ 〜 資料・動画・リポジトリのご利用について〜
公開している資料や動画は、是非、勉強会や社内の研修などにご自由にお使いいただければと思いますが、以下のような場でのご利用はご遠慮ください。
- 受講者から参加費や授業料など金銭を集めるような場での利用
(会場費や飲食費など勉強会の運営に必要な実費を集める場合は問題ありません)
- 出典を削除または改変しての利用

MIXI ENGINEERS

July 22, 2024
Tweet

Video

More Decks by MIXI ENGINEERS

Other Decks in Technology

Transcript

  1. 1 Android 2 3 UI 4 5 6 7 8

    9 UI 10 Kotlin Multiplatform
  2. ©MIXI Android 9 API (SDK ) 2008.09 1.0 1 Base

    ... 2018.08 9 28 Pie 2019.09 10 29 Q 2020.09 11 30 R 2021.10 12 31 S 2022.03 12L 32 S v2 2022.08 13 33 Tiramisu 2023.10 14 34 UpsideDownCake - 15 35 VanillaIceCream API ( )
  3. ©MIXI 13 Android Studio AAB (Android App Bundle) Google Play

    : : xxhdpi CPU: arm : : hdpi CPU: x86 APK
  4. ©MIXI 14 Android Studio AAB (Android App Bundle) Google Play

    l l : : xxhdpi CPU: arm : : hdpi CPU: x86
  5. ©MIXI Kotlin Android (2017 ) Java 15 Kotlin l :

    l Java : Kotlin Java Java Kotlin l Null :
  6. ©MIXI l : l Java : Kotlin Java Java Kotlin

    l Null : Kotlin Android (2017 ) Java 16 Kotlin NullPointerException var count: Int // null var count: Int? // null
  7. ©MIXI Kotlin Android, iOS, Desktop, Web https://kotlinlang.org/docs/multiplatform.html 17 Kotlin Multiplatform

    Kotlin UI ( ) https://developerhttps://developer.android.com/develop/ui/compose?hl=ja Jetpack Compose
  8. ©MIXI Wear OS, ChromeOS, Android TV, Android Auto API :

    Android 14 API 34, UpsideDownCake APK : AAB : Google Play APK : , Java , Null Kotlin : Kotlin Multiplatform, Jetpack Compose 18 Android Kotlin
  9. 2

  10. ©MIXI ( ) 1. Android 11 PC 2. https://developer.android.com/studio/debug/dev-options?hl=ja#enable 3.

    Android Studio Pair Devices Using Wi-Fi 4. ON 5. Android Studio 6. Android Studio 26 2. Wi-Fi
  11. ©MIXI : 1. Android Studio Get from VCS 28 2.

    URL [email protected]:mixigroup/2024AndroidTraining.git git clone OK 3. app.ui 1
  12. ©MIXI Jetpack l l 29 app Android 14 Android 13

    Android 12 if else if else ... app Android 14 Android 13 Android 12 Jetpack
  13. ©MIXI Jetpack Compose Jetpack Kotlin UI 2021 UI ( )

    https://developer.android.com/develop/ui/compose?hl=ja 30
  14. ©MIXI 31 View : UI Compose : UI val textView

    = TextView(context) textView.setText("Hello") textView.setTextColor(Color.BLUE) Text( text = "Hello", color = Color.Blue, ) View UI View Composable UI Composable
  15. ©MIXI 32 View : UI Compose : UI val textView

    = TextView(context) textView.setText("Hello") textView.setTextColor(Color.BLUE) Text( text = "Hello", color = Color.Blue, ) Composable UI Composable UI Recompose
  16. ©MIXI Composable 33 @Composable fun RedText( text: String, modifier: Modifier

    = Modifier, ) { Text( text = text, modifier = modifier, color = Color.Red ) } RedText( text = "Red text", ) RedText( text = "Red text with blue background", modifier = Modifier.background(Color.Blue), )
  17. ©MIXI Composable 34 @Composable fun RedText( text: String, modifier: Modifier

    = Modifier, ) { Text( text = text, modifier = modifier, color = Color.Red, ) } Composable Compose Composable l ProfileScreen l LoginButton l HeaderImage
  18. ©MIXI Composable 35 // modifier RedText( text = "Red text",

    ) // modifier RedText( text = "Red text with blue background", modifier = Modifier.background(Color.Blue), ) text = modifier API
  19. ©MIXI Composable Composable Composable Composable e.g. Button, Tab, Snackbar 36

    Snackbar { Text(text = "Hello") } Composable Snackbar: UI
  20. ©MIXI Composable 37 @Composable fun Snackbar( ... content: @Composable ()

    -> Unit ) Snackbar(content = { Text(text = "Hello") }) Snackbar() { Text(text = "Hello") } Snackbar { Text(text = "Hello") } ( ) -> () -> Unit { -> } () ()
  21. ©MIXI Modifier.padding(all = 8.dp) Modifier.padding(horizontal = 8.dp, vertical = 4.dp)

    Modifier.padding(start = 8.dp, top = 4.dp, end = 8.dp, bottom = 16.dp) Modifier 39 // 96 x 48 dp Modifier.width(96.dp).height(48.dp) // 48 x 48 dp Modifier.size(48.dp) // Modifier.fillMaxWidth().wrapContentHeight() // Modifier.fillMaxSize() dp
  22. ©MIXI Composable 44 Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(8.dp),

    ) { Text(text = "Top") Text(text = "Center") Text(text = "Bottom") } Composable (36 )
  23. ©MIXI Composable Spacer 45 Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(text =

    "Top") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Center") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Bottom") }
  24. ©MIXI 46 Column(modifier = modifier.height(160.dp)) { Text(text = "Top", modifier

    = Modifier.weight(1f)) Text(text = "Center") Text(text = "Bottom") } Column(modifier = modifier.height(160.dp)) { Text(text = "Top", modifier = Modifier.weight(1f)) Text(text = "Center", modifier = Modifier.weight(2f)) Text(text = "Bottom", modifier = Modifier.weight(3f)) } 1:2:3 ⾒
  25. ©MIXI Composable 47 Row( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically,

    ) { Text(text = "Left") Text(text = "Center") Text(text = "Right") } Row : Column
  26. ©MIXI : LazyColumn Compose 48 Column LazyColumn Compose Item 1

    Item 2 Item 3 Item 4 Item 5 Item 6 Item 7 Item 8 Item 1 Item 2 Item 3 Item 4 Item 5 Item 6 Item 7 Item 8 Compose
  27. ©MIXI LazyColumn LazyRow 49 LazyColumn( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement =

    Arrangement.spacedBy(8.dp), ) { // 1 item { Text(text = "Header") } // items(listOf("1", "2", "3")) { text -> Text(text = text) } }
  28. ©MIXI 3.1 app.ui BookItem 52, 53 51 16 dp 8

    dp 8 dp 4 dp 18 sp, 16 sp 16 dp title author
  29. ©MIXI 3.1 @Preview 52 app.ui UiScreen @Composable fun UiScreen(modifier: Modifier

    = Modifier) { Column(...) { ... val book = Book(title = " ", author = " ") BookItem(book = book) ... } } 1 2
  30. ©MIXI UI 55 Jetpack UI Kotlin Jetpack Compose Composable UI

    Modifier Composable Column , Row , LazyColumn / LazyRow DP , SP
  31. 4

  32. ©MIXI Android 57 ( ) l String resource l Drawable

    resource l Raw resource src/main/res/
  33. ©MIXI res/values/strings.xml 58 <resources> <string name="login"> </string> <string name="settings"> </string>

    ... </resources> Text(text = stringResource(id = R.string.login)) Text(text = stringResource(id = R.string.settings)) UI
  34. ©MIXI Icon( painter = painterResource(id = R.drawable.ramen), contentDescription = stringResource(R.string.ramen),

    tint = Color.Red, ) 64 Image( painter = painterResource(id = R.drawable.ramen), contentDescription = stringResource(R.string.ramen), ) Icon
  35. ©MIXI Modifier 65 Image( ... modifier = Modifier.clip(CircleShape), ) Image(

    ... modifier = Modifier.clip(RoundedCornerShape(size = 8.dp)), )
  36. ©MIXI 8dp padding 4.2 BookItem 67 16 dp 16 dp

    48 x 48 dp l Android Studio l Modifier (35 ) l Modifier : https://developer.android.com/jetpack/compose/modifiers?hl=ja#order-modifier-matters
  37. 5

  38. ©MIXI 1 : 74 var count = 0 Button(onClick =

    { count++ }) { Text(text = count.toString()) } count Recompose val : var : 0 0
  39. ©MIXI 1 : 75 var count by remember { mutableStateOf(0)

    } Button(onClick = { count++ }) { Text(text = count.toString()) } MutableState Compose Recompose (UI )
  40. ©MIXI 1 : 76 var count by remember { mutableStateOf(0)

    } Button(onClick = { count++ }) { Text(text = count.toString()) } Delegated property MutableState<Int> Int remember Recompose API : https://developer.android.com/jetpack/compose/state#state-in-composables
  41. ©MIXI 1 : 77 var count by remember { mutableStateOf(0)

    } Button(onClick = { count++ }) { Text(text = count.toString()) } 0 1
  42. ©MIXI var text by remember { mutableStateOf("") } TextField( value

    = text, onValueChange = { value -> text = value } ) 2 : 78
  43. ©MIXI 81 Composable (Recompose) UI MutableState Recompose var state by

    remember { mutableStateOf( ) } UI Composable onClick onValueChange e.g. Button, TextField, Switch UI UI
  44. 6

  45. ©MIXI 87 val TAG = "LoginScreen" Log.v(TAG, " ") Log.d(TAG,

    " ") Log.i(TAG, " ") Log.w(TAG, " ") Log.e(TAG, " ") ( )
  46. 7

  47. ©MIXI UI 94 UI UI Compose l UI l UI

    ViewModel l UI l UI UI
  48. ©MIXI : ver. 98 Column(...) { var result by remember

    { mutableStateOf("") } Text(text = result) Button(onClick = { result = listOf(" ", " ", ...).random() }) { Text(text = stringResource(R.string.pick_omikuji)) } }
  49. ©MIXI ( ) 100 class OmikujiRepository { fun getResult(): String

    { return listOf(" ", " ", ...).random() } }
  50. ©MIXI UI 102 data class OmikujiUiState( val result: String =

    "", ) : class OmikujiUiState( val result: String = "", ) { fun copy(result: String = this.result) = OmikujiUiState(result) override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is OmikujiUiState) return false return result == other.result } override fun toString() = "ResultUiState(result='$result')" override fun hashCode() = result.hashCode() }
  51. ©MIXI UiState MutableState 105 class OmikujiViewModel(...) : ViewModel() { var

    uiState by mutableStateOf(OmikujiUiState()) } uiState = uiState.copy(result = " ")
  52. ©MIXI UiState ViewModel 106 class OmikujiViewModel(...) : ViewModel() { ...

    fun pick() { val result = repository.getResult() uiState = uiState.copy(result = result) } } UiState UI
  53. ©MIXI UI ViewModel 107 val viewModel: OmikujiViewModel = viewModel() val

    uiState = viewModel.uiState Text(text = uiState.result) var result by remember { mutableStateOf("") } Text(text = result) Before After Compose ViewModel
  54. ©MIXI Button(onClick = viewModel::pick) UI ViewModel 108 Button(onClick = {

    viewModel.pick() }) Button(onClick = { result = listOf(" ", " ", ...).random() }) Before After OK https://kotlinlang.org/docs/reflection.html#function-references
  55. 8

  56. ©MIXI ViewModel 118 class OmikujiViewModelTest { private val viewModel =

    OmikujiViewModel() @Test fun testPick() { assertEquals("", viewModel.uiState.result) viewModel.pick() assertNotEquals("", viewModel.uiState.result) } }
  57. ©MIXI ViewModel 119 class OmikujiViewModelTest { private val viewModel =

    OmikujiViewModel() @Test fun testPick() { assertEquals("", viewModel.uiState.result) viewModel.pick() assertNotEquals("", viewModel.uiState.result) } } JUnit 4 (Java ) API
  58. ©MIXI ViewModel 120 class OmikujiViewModelTest { private val viewModel =

    OmikujiViewModel() @Test fun testPick() { assertEquals("", viewModel.uiState.result) viewModel.pick() assertNotEquals("", viewModel.uiState.result) } } uiState
  59. ©MIXI ViewModel 121 class OmikujiViewModelTest { private val viewModel =

    OmikujiViewModel() @Test fun testPick() { assertEquals("", viewModel.uiState.result) viewModel.pick() assertEquals(" ", viewModel.uiState.result) } }
  60. ©MIXI 123 class OmikujiViewModel( private val repository: OmikujiRepository, ) :

    ViewModel() DefaultOmikujiRepository FakeOmikujiRepository (104 )
  61. ©MIXI 124 interface OmikujiRepository { fun getResult(): String } class

    DefaultOmikujiRepository : OmikujiRepository { override fun getResult(): String { return listOf(" ", " ", ...).random() } } class FakeOmikujiRepository : OmikujiRepository { override fun getResult(): String { return " " } }
  62. ©MIXI 125 class OmikujiViewModelTest { private val viewModel = OmikujiViewModel(FakeOmikujiRepository())

    @Test fun testPick() { assertEquals("", viewModel.uiState.result) viewModel.pick() assertEquals(" ", viewModel.uiState.result) } }
  63. 9

  64. ©MIXI 133 data class WeatherUiState( val weather: String = "",

    val isLoading: Boolean = false, ) fun getWeather() { // uiState = uiState.copy(isLoading = true) // val weather = repository.getWeather() // uiState = uiState.copy(weather = weather, isLoading = false) } ViewModel
  65. ©MIXI 134 data class WeatherUiState( val weather: String = "",

    val isLoading: Boolean = false ) fun getWeather() { // uiState = uiState.copy(isLoading = true) // val weather = repository.getWeather() // uiState = uiState.copy(weather = weather, isLoading = false) } ViewModel (UI )
  66. ©MIXI Kotlin 135 viewModelScope.launch { uiState = uiState.copy(isLoading = true)

    val weather = repository.getWeather() uiState = uiState.copy(weather = weather, isLoading = false) } uiState = uiState.copy(isLoading = true) val weather = repository.getWeather() uiState = uiState.copy(weather = weather, isLoading = false)
  67. ©MIXI Kotlin 136 viewModelScope.launch { uiState = uiState.copy(isLoading = true)

    val weather = repository.getWeather() uiState = uiState.copy(weather = weather, isLoading = false) } getWeather()
  68. ©MIXI suspend 139 Kotlin API delay(timeMillis = 2000) 2 Ktor

    (HTTP ) API val response = client.request(urlString = "https://...") DB Jetpack Room (SQLite ) API val user = dao.getUser(userId = ...)
  69. ©MIXI 9.2 ( ) : SNS 9.1 ViewModel app.weather :

    https://developer.android.com/kotlin/coroutines/test?hl=ja 142 l l UiState
  70. ©MIXI 143 UI l l suspend l suspend l suspend

    l suspend suspend e.g. , DB
  71. ©MIXI 10.1 : Kotlin Multiplatform multiplatform Android / iOS /

    Desktop 145 https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-multiplatform-setup.html ü Xcode ü Kotlin Multiplatform Mobile plugin ü Xcode ü KDoctor
  72. ©MIXI Compose, , , , https://github.com/android/nowinandroid 150 https://www.jetbrains.com/help/kotlin-multiplatform-dev/multiplatform-samples.html Compose UI

    https://github.com/android/compose-samples Now in Android App Kotlin Multiplatform Samples Jetpack Compose Samples