It's a Kotlin, Kotlin, Kotlin World (London Android Meetup July 2017)

It's a Kotlin, Kotlin, Kotlin World (London Android Meetup July 2017)

Kotlin's popularity has exploded in the past year and Google's announcement of first-party support at I/O means it's only going to keep increasing. Now is the perfect time to jump on the language as its future in mobile and beyond is very bright. This talk will take a look at where the language is headed and see if it can deliver on a promise of cross-platform use.

Video: https://youtu.be/CtZL_IjR5Ww

E68309f117985270285ade8082f4877d?s=128

Jake Wharton

July 25, 2017
Tweet

Transcript

  1. IT'S A KOTLIN, KOTLIN, KOTLIN WORLD! JAKE WHARTON PRESENTS

  2. None
  3. X

  4. X O X X X O

  5. X O X X X O O O X

  6. XOPlayer X X X O O O X XOPlayer

  7. iOS Web Server / API Android

  8. app/

  9. app/ wear/

  10. app/ wear/ common/

  11. app/ wear/ common/

  12. wear/ common/ app/

  13. app/ wear/ common/

  14. app/ wear/ common/

  15. app/ wear/ util/ common/

  16. app/ wear/ common/ util/ models/

  17. None
  18. package xo; public enum Mark { X, O; }

  19. package xo; import java.util.Arrays; public final class Board { private

    static final int SIZE = 3; private final Mark[][] cells; public Board() { this.cells = new Mark[3][3]; } // TODO mutator methods... @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Board)) return false; Board other = (Board) o; return Arrays.deepEquals(cells, other.cells); } @Override public int hashCode() { return Arrays.deepHashCode(cells);
  20. package xo; import static java.util.Objects.requireNonNull; public final class Player {

    public final String name; public final Mark mark; public Player(String name, Mark mark) { this.name = requireNonNull(name, "name == null"); this.mark = requireNonNull(mark, "mark == null"); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Player)) return false; Player other = (Player) o; return name.equals(other.name) && mark == other.mark; } @Override public int hashCode() { return 31 * name.hashCode() + mark.hashCode(); }
  21. package xo; public enum State { PLAYER_1_MOVE, PLAYER_2_MOVE, PLAYER_1_WIN, PLAYER_2_WIN,

    DRAW, }
  22. package xo; import static java.util.Objects.requireNonNull; public final class Game {

    private final Board board; private final Player player1; private final Player player2; private State state = State.PLAYER_1_MOVE; public Game(Board board, Player player1, Player player2) { this.board = requireNonNull(board, "board == null"); this.player1 = requireNonNull(player1, "player1 == null"); this.player2 = requireNonNull(player2, "player2 == null"); } // TODO mutator methods... @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Game)) return false; Game other = (Game) o; return board.equals(other.board) && player1.equals(other.player1)
  23. Game Board Mark State Player

  24. public final class Player { public final String name; public

    final Mark mark; public Player(String name, Mark mark) { this.name = requireNonNull(name, "name == null"); this.mark = requireNonNull(mark, "mark == null"); }A @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Player)) return false; Player other = (Player) o; return name.equals(other.name) && mark == other.mark; }B @Override public int hashCode() { return 31 * name.hashCode() + mark.hashCode(); }C @Override public String toString() { return "Player{name='" + name + ", mark=" + mark + '}'; }D }E
  25. data class Player(val name: String, val mark: Mark) public final

    { public final ; public final ; public Player(String name, Mark mark) { this.name = requireNonNull(name, "name == null"); this.mark = requireNonNull(mark, "mark == null"); }A @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Player)) return false; Player other = (Player) o; return name.equals(other.name) && mark == other.mark; }B @Override public int hashCode() { return 31 * name.hashCode() + mark.hashCode(); }C @Override public String toString() { return "Player{name='" + name + ", mark=" + mark + '}'; }D }E
  26. Game Mark State Board Player

  27. State Board Game Mark Player

  28. Game Mark State Board *.java *.kt Player

  29. *.kt Game Mark State *.java

  30. kotlinc *.kt Game Mark State *.java

  31. *.kt Game Mark State *.java kotlinc

  32. javac *.kt Game Mark State *.java kotlinc

  33. javac *.kt Game Mark State *.java kotlinc

  34. kotlinc javac *.kt Game Mark State *.java

  35. kotlin-stdlib kotlinc javac *.kt Game Mark State *.java

  36. kotlin-stdlib kotlinc javac *.kt Game Mark State *.java models/

  37. kotlin-stdlib kotlinc javac *.kt Game Mark State *.java models/

  38. kotlin-stdlib kotlinc javac *.kt Game Mark State *.java models/

  39. kotlin-stdlib kotlinc javac *.kt Game Mark State *.java

  40. kotlin-stdlib kotlinc Game Mark State javac *.kt *.java

  41. kotlin-stdlib kotlinc Game Mark State javac *.kt *.java

  42. kotlin-stdlib kotlinc State Mark Game javac *.kt *.java

  43. kotlin-stdlib kotlinc State *.java Mark Game javac *.kt

  44. kotlin-stdlib kotlinc *.java State Mark Game *.kt

  45. app/ wear/ common/ util/ models/ kotlin-stdlib kotlinc *.java State Mark

    Game *.kt
  46. app/ wear/ common/ util/ models/

  47. Server / API iOS Web Android app/ wear/ common/ util/

    models/
  48. Server / API iOS Web Android app/ wear/ util/ models/

    common/
  49. Server / API iOS Web Android app/ wear/ util/ models/

    common/
  50. Server / API iOS Web Android app/ wear/ util/ models/

    common/
  51. Server / API iOS Web Android app/ wear/ util/ models/

    common/ protos
  52. iOS Web Server / API Android

  53. iOS Web Server / API Android

  54. iOS Web Server / API Android View Models

  55. iOS Web Server / API Android View Models Presenters

  56. iOS Web Server / API Android View Models Presenters

  57. iOS Web Server / API Android View Models Presenters Client

    Backend
  58. iOS Web Server / API Android View Models Presenters Client

    Backend
  59. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic
  60. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  61. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  62. data class NewGameUiModel( val winTotal: Long, val lossTotal: Long )

  63. data class NewGameUiModel( val winTotal: Long, val lossTotal: Long )

    data class GameUiModel( val game: Game )
  64. data class NewGameUiModel( val winTotal: Long, val lossTotal: Long )

    data class GameUiModel( ) val game: Game
  65. data class NewGameUiModel( val winTotal: Long, val lossTotal: Long )

    data class GameUiModel( val game: Game )
  66. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  67. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  68. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  69. class NewGamePresenter {C fun model(): NewGameUiModel { }B }A

  70. class NewGamePresenter(private val gameStore: GameStore) {C fun model(): NewGameUiModel {

    }B }A
  71. class NewGamePresenter(private val gameStore: GameStore) {C fun model(): NewGameUiModel {

    val totals = gameStore.totals() return NewGameUiModel(totals.wins, totals.losses) }B }A
  72. class GamePresenter {D fun model(): GameUiModel {C }B }A

  73. class GamePresenter(private val gameId: Long) {D fun model(): GameUiModel {C

    }B }A
  74. class GamePresenter( private val gameId: Long, private val gameStore: GameStore

    ) {D fun model(): GameUiModel {C }B }A
  75. class GamePresenter( private val gameId: Long, private val gameStore: GameStore

    ) {D fun models(): Observable<GameUiModel> {C }B }A
  76. class GamePresenter( private val gameId: Long, private val gameStore: GameStore

    ) {D fun move(row: Int, col: Int)Z{C }G fun models(): Observable<GameUiModel> {C }B }A
  77. class GamePresenter( private val gameId: Long, private val gameStore: GameStore

    ) {D fun models(events: Observable<UiEvent>): Observable<GameUiModel> {C }B sealed class UiEvent { data class Move(val row: Int, val col: Int): UiEvent() // ... } }A fun move( )Z{C }G
  78. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  79. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  80. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  81. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  82. interface GameStore { }A

  83. interface GameStore { fun totals(): Single<Totals> data class Totals(val wins:

    Long, val losses: Long) }A
  84. interface GameStore { fun totals(): Single<Totals> fun game(id: Long): Observable<Game>

    data class Totals(val wins: Long, val losses: Long) }A
  85. interface GameStore { fun totals(): Single<Totals> fun game(id: Long): Observable<Game>

    fun move(id: Long, row: Int, col: Int): Completable data class Totals(val wins: Long, val losses: Long) }A
  86. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  87. iOS Web Server / API Android View Models Presenters Client

    Backend Business Logic Models
  88. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  89. class SqliteGameStore(private val db: SQLiteDatabase) : GameStore { override fun

    totals() = TODO() override fun game(id: Long) = TODO() override fun move(id: Long, row: Int, col: Int) = TODO() }
  90. class IosGameStore(private val db: CoreDataGameStore) : GameStore { override fun

    totals() = TODO() override fun game(id: Long) = TODO() override fun move(id: Long, row: Int, col: Int) = TODO() }
  91. class IosGameStore( ) : GameStore { override fun totals() =

    TODO() override fun game(id: Long) = TODO() override fun move(id: Long, row: Int, col: Int) = TODO() } private val db: CoreDataGameStore
  92. class IosGameStore( ) : GameStore { override fun totals() =

    TODO() override fun game(id: Long) = TODO() override fun move(id: Long, row: Int, col: Int) = TODO() } private val db: CoreDataGameStore // tictactoe.def headers = game_store.h
  93. class StorageGameStore(private val store: Storage) : GameStore { override fun

    totals() = TODO() override fun game(id: Long) = TODO() override fun move(id: Long, row: Int, col: Int) = TODO() }A
  94. import org.w3c.dom.Storage class StorageGameStore( ) : GameStore { override fun

    totals() = TODO() override fun game(id: Long) = TODO() override fun move(id: Long, row: Int, col: Int) = TODO() }A private val store: Storage
  95. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  96. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  97. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  98. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  99. object TicTacToeLogic { fun validateMove( game: Game, player: Player, row:

    Int, col: Int): Boolean { when (game.state) { State.PLAYER_1_MOVE -> require(game.player1 == player) State.PLAYER_2_MOVE -> require(game.player2 == player) else -> error("Game is over") } return game.board[row][col] == null } fun nextState(game: Game): State { findWinner(game.board)?.let { return if (game.player1.mark == it) State.PLAYER_1_WIN else State.PLAYER_2_WIN } if (game.board.isComplete()) { return State.DRAW } return if (game.state == State.PLAYER_1_MOVE) State.PLAYER_2_MOVE else State.PLAYER_1_MOVE } fun findWinner(board: Board): Mark? = TODO() fun Board.isComplete(): Boolean = TODO() }
  100. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  101. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  102. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  103. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  104. class GameView(context: Context, attrs: AttributeSet) : Consumer<GamePresenter.UiModel> { fun accept(model:

    GamePresenter.UiModel) { // TODO bind to view... } }
  105. iOS???

  106. function update(model) { // TODO bind to DOM/template/JSX/whatever... }

  107. @POST @Path("/api/move") fun Game move( @QueryParam("id") id: Long, @QueryParam("row") row:

    Int, @QueryParam("col") col: Int) { // TODO check business logic, persist, return udpated game ... }
  108. Android iOS Web iOS Web Server / API Android View

    Models Presenters Client Backend Business Logic Models
  109. X O X X X O O O X

  110. IT'S A KOTLIN, KOTLIN, KOTLIN WORLD! @JAKEWHARTON