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

Android Jetpack Compose

MOSDROID
September 13, 2019

Android Jetpack Compose

Антон Зинаков, Mail.Ru Group at #MOSDROID 19 Potassium [in KasperskyLab HeadQuarter]

На текущий момент основной способ написания UI в Android — XML разметка. Такой подход тянется уже около 10 лет и имеет свои проблемы: совместимость с предыдущими версиями ОС, достаточный объем legacy в самих классах View, относительно сложно переиспользовать написанные элементы.

В докладе я расскажу про опыт использования Jetpack Compose представленного на I/O 2019 – декларативный фреймворк для создания UI с использованием Kotlin. Это большой шаг вперед и огромный задел на будущее Android: Jetpack Compose во многом решает проблемы сегодняшнего UI, упрощает и вносит современный подход в разработку.

MOSDROID

September 13, 2019
Tweet

More Decks by MOSDROID

Other Decks in Programming

Transcript

  1. Jetpack Compose

    View Slide

  2. User Interface today
    • XML & View

    View Slide

  3. User Interface today
    • XML & View

    • 2009

    View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. User Interface today
    • XML & View

    • 2009

    • Compatibility problems

    View Slide

  8. View Slide

  9. View Slide

  10. User Interface today
    • XML & View

    • 2009

    • Compatibility problems

    • Hard to display the same UI on different devices and Android versions

    View Slide

  11. User Interface today
    • XML & View

    • 2009

    • Compatibility problems

    • Hard to display the same UI on different devices and Android versions

    • Reusability is not convenient

    View Slide

  12. Alternative UI frameworks

    View Slide

  13. Alternative UI frameworks

    View Slide

  14. Alternative UI frameworks

    View Slide

  15. Jetpack Compose

    View Slide

  16. Jetpack Compose
    • Declarative

    View Slide

  17. Jetpack Compose
    • Declarative

    • Kotlin

    View Slide

  18. Jetpack Compose
    • Declarative

    • Kotlin

    • Compatibility with different Android versions

    View Slide

  19. Jetpack Compose
    • Declarative

    • Kotlin

    • Compatibility with different Android versions

    • Easy to reuse

    View Slide

  20. Jetpack Compose
    • Declarative

    • Kotlin

    • Compatibility with different Android versions

    • Easy to reuse

    • Modern

    View Slide

  21. Let’s try it!

    View Slide

  22. Install REPO
    mkdir ~/bin
    PATH=~/bin:$PATH
    curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    chmod a+x ~/bin/repo

    View Slide

  23. Configure GIT
    git config --global user.name "Your Name"
    git config --global user.email "[email protected]"

    View Slide

  24. Create directory for checkout
    mkdir androidx-master-dev
    cd androidx-master-dev

    View Slide

  25. Initialize the repository
    repo init -u https://android.googlesource.com/platform/manifest
    -b androidx-master-dev

    View Slide

  26. Download the code (about 6GB)
    repo sync -j8 -c

    View Slide

  27. Change directory
    path/to/compose/frameworks/support/ui/

    View Slide

  28. and run…
    ./studiow

    View Slide

  29. How to print text?
    fun main() {
    print("Hello, Mosdroid!")
    }

    View Slide

  30. How to draw text on Android UI?
    @Composable
    fun Greeting() {
    Text(text = "Hello, Mosdroid!")
    }

    View Slide

  31. class MosdroidActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    Greeting()
    }
    }
    @Composable
    fun Greeting() {
    Text(text = "Hello, Mosdroid!")
    }
    }

    View Slide

  32. @Composable
    fun Greeting() {
    Text(text = "Hello, Mosdroid!")
    }

    View Slide

  33. @Composable
    fun Greeting() {
    Text(
    text = "Hello, Mosdroid!",
    style = TextStyle(fontSize = 48.sp)
    )
    }

    View Slide

  34. @Composable
    fun Greeting() {
    Align(Alignment.Center) {
    Text(
    text = "Hello, Mosdroid!",
    style = TextStyle(fontSize = 48.sp)
    )
    }
    }

    View Slide

  35. Real example
    • I want to create an application with possibility to add persons and display
    added person in list

    • I want to separate UI elements to two independent widgets

    View Slide

  36. Dummy implementation
    @Composable
    fun PersonEditorWidget() {
    Column {
    TextField(EditorModel())
    Button(text = "Add Person")
    }
    }

    View Slide

  37. Dummy implementation
    @Composable
    fun PersonEditorWidget() {
    Column {
    TextField(EditorModel())
    Button(text = "Add Person")
    }
    }

    View Slide

  38. data class PersonEditorModel(
    val name: String = "",
    val buttonTitle: String = "Add Person",
    val onClick: (String) -> Unit
    )

    View Slide

  39. data class PersonEditorModel(
    val name: String = "",
    val buttonTitle: String = "Add Person",
    val onClick: (String) -> Unit
    )
    @Composable
    fun PersonEditorWidget(model: PersonEditorModel) {
    Column {
    val nameState = +state { EditorModel(model.name) }
    TextField(
    value = nameState.value,
    onValueChange = { nameState.value = it },
    editorStyle = EditorStyle(
    textStyle = TextStyle(fontSize = 24.sp)
    )
    )
    Button(
    text = model.buttonTitle,
    onClick = { model.onClick(nameState.value.text) }
    )
    }
    }

    View Slide

  40. @Composable
    fun PersonEditorWidget(model: PersonEditorModel) {
    Column {
    val nameState = +state { EditorModel(model.name) }
    TextField(
    value = nameState.value,
    onValueChange = {
    nameState.value = it
    },
    editorStyle = EditorStyle(
    textStyle = TextStyle(fontSize = 24.sp)
    )
    )
    Button(
    text = model.buttonTitle,
    onClick = {
    model.onClick(nameState.value.text)
    }
    )
    }
    }
    Padding(16.dp) {
    }

    View Slide

  41. @Composable
    fun PersonEditorWidget(model: PersonEditorModel) {
    Padding(16.dp) {
    Column {
    val nameState = +state { EditorModel(model.name) }
    TextField(
    value = nameState.value,
    onValueChange = {
    nameState.value = it
    },
    editorStyle = EditorStyle(
    textStyle = TextStyle(fontSize = 24.sp)
    )
    )
    Button(
    text = model.buttonTitle,
    onClick = {
    model.onClick(nameState.value.text)
    }
    )
    }
    }
    }
    FlexRow {
    expanded(1.0f) {
    }
    }

    View Slide

  42. @Composable
    fun PersonEditorWidget(model: PersonEditorModel) {
    Padding(16.dp) {
    Column {
    val nameState = +state { EditorModel(model.name) }
    TextField(
    value = nameState.value,
    onValueChange = {
    nameState.value = it
    },
    editorStyle = EditorStyle(
    textStyle = TextStyle(fontSize = 24.sp)
    )
    )
    HeightSpacer(12.dp)
    FlexRow {
    expanded(1.0f) {
    Button(
    text = model.buttonTitle,
    onClick = {
    model.onClick(nameState.value.text)
    }
    )
    }
    }
    }

    View Slide

  43. @Composable
    fun PersonListWidget(persons: List) {
    Column {
    persons.forEachIndexed { index, person ->
    Align(Alignment.TopLeft) {
    Padding(16.dp) {
    Text(
    text = person.name,
    style = TextStyle(fontSize = 18.sp)
    )
    }
    }
    }
    }
    }

    View Slide

  44. @Composable
    fun PersonListWidget(persons: List) {
    val dividerColor = Color(0xFFC6C6C6)
    Column {
    persons.forEachIndexed { index, person ->
    Align(Alignment.TopLeft) {
    Padding(16.dp) {
    Text(
    text = person.name,
    style = TextStyle(fontSize = 18.sp)
    )
    }
    }
    if (index != persons.lastIndex) {
    Divider(
    color = dividerColor,
    height = 0.5.dp
    )
    }
    }
    }
    }

    View Slide

  45. @Composable
    fun Dashboard(persons: MutableList) {
    val state = +state { persons }
    Column {
    PersonEditorWidget(
    PersonEditorModel(
    name = "Anton",
    onClick = {
    state.value = state.value.apply {
    add(Person(it))
    }
    }
    ))
    Divider()
    PersonListWidget(state.value)
    }
    }

    View Slide

  46. Add theme

    View Slide

  47. private val colorGreen = Color(0xFF1B5E20.toInt())
    @Composable
    fun MosdroidTheme(@Children children: @Composable() () -> Unit) {
    val colors = MaterialColors(primary = colorGreen)
    val typography = MaterialTypography(
    h5 = TextStyle(
    fontFamily = FontFamily("Roboto"),
    fontWeight = FontWeight.w700,
    fontSize = 24.sp
    ),
    h6 = TextStyle(
    fontFamily = FontFamily("Roboto"),
    fontWeight = FontWeight.w700,
    fontSize = 18.sp
    ),
    button = TextStyle(
    fontFamily = FontFamily("Roboto"),
    fontWeight = FontWeight.w800,
    fontSize = 14.sp
    )
    )
    MaterialTheme(colors = colors, typography = typography) {
    children()
    }
    }

    View Slide

  48. override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    MosdroidTheme {
    Dashboard(personList)
    }
    }
    }

    View Slide

  49. @Composable
    fun PersonEditorWidget(model: PersonEditorModel) {
    Padding(16.dp) {
    Column {
    val nameState = +state { EditorModel(model.name) }
    TextField(
    value = nameState.value,
    onValueChange = {
    nameState.value = it
    },
    editorStyle = EditorStyle(
    textStyle = TextStyle(fontSize = 24.sp)
    )
    )
    HeightSpacer(12.dp)
    FlexRow {
    expanded(1.0f) {
    Button(
    text = model.buttonTitle,
    onClick = {
    model.onClick(nameState.value.text)
    }
    )
    }
    }
    }

    View Slide

  50. @Composable
    fun PersonEditorWidget(model: PersonEditorModel) {
    Padding(16.dp) {
    Column {
    val nameState = +state { EditorModel(model.name) }
    TextField(
    value = nameState.value,
    onValueChange = {
    nameState.value = it
    },
    editorStyle = EditorStyle(
    textStyle = +themeTextStyle { h5 }
    )
    )
    HeightSpacer(12.dp)
    FlexRow {
    expanded(1.0f) {
    Button(
    text = model.buttonTitle,
    onClick = {
    model.onClick(nameState.value.text)
    }
    )
    }
    }
    }

    View Slide

  51. View Slide

  52. View Slide

  53. Didn’t covered
    • Animations

    • Complex layout

    • Internal principles

    View Slide

  54. Links
    • Official resource: https://developer.android.com/jetpack/compose

    • Jetpack Compose Principles: http://intelligiblebabble.com/compose-from-
    first-principles/

    • Example: https://medium.com/q42-engineering/android-jetpack-
    compose-895b7fd04bf4

    • Compose Readme: https://android.googlesource.com/platform/
    frameworks/support/+/refs/heads/androidx-master-dev/ui/README.md

    View Slide

  55. Conclusion
    • pre-alpha

    View Slide

  56. Conclusion
    • pre-alpha

    • No good instruments

    View Slide

  57. Conclusion
    • pre-alpha

    • No good instruments

    • UI tests?

    View Slide

  58. Conclusion
    • pre-alpha

    • No good instruments

    • UI tests?

    • Functions - small UI components

    View Slide

  59. Conclusion
    • pre-alpha

    • No good instruments

    • UI tests?

    • Functions - small UI components

    • Android version independent

    View Slide

  60. Conclusion
    • pre-alpha

    • No good instruments

    • UI tests?

    • Functions - small UI components

    • Android version independent

    • Less boilerplate

    View Slide

  61. Questions?
    Zinakov Anton
    Android Developer
    [email protected]
    @rygital

    View Slide