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

Inside Jetpack

Inside Jetpack

kobito-kaba

November 28, 2018
Tweet

More Decks by kobito-kaba

Other Decks in Programming

Transcript

  1. Inside Jetpack
    Architecture Components
    Hiroyuki Mori
    @moridroid

    View Slide

  2. • Started as a Venture between Softbank and Yahoo
    • One of biggest search in Japan
    • Not a part of big

    View Slide

  3. What & Why
    Architecture Components

    View Slide

  4. 2015

    View Slide

  5. View
    View
    Controller
    Application
    Logic
    Network
    Persistent
    Model
    onSendClick
    sendComment

    View Slide

  6. onSendClick
    sendComment
    View
    View
    Controller
    Application
    Logic
    Network
    Persistent
    Model

    View Slide

  7. View
    View
    Controller
    Application
    Logic
    Network
    Persistent
    Model

    View Slide

  8. View
    View
    Controller
    Application
    Logic
    Network
    Persistent
    Model
    subscribe

    View Slide

  9. View
    View
    Controller
    Application
    Logic
    Network
    Persistent
    Model
    onSendClick
    sendComment

    View Slide

  10. 2016

    View Slide

  11. View Slide

  12. 2016

    View Slide

  13. 2017

    View Slide

  14. 2017

    View Slide

  15. 2017

    View Slide

  16. 2018

    View Slide

  17. 2018
    -JGFDZDMFT
    -JWF%BUB
    7JFX.PEFM
    3PPN
    1BHJOH
    %BUB#JOEJOH
    /BWJHBUJPO
    8PSL.BOBHFS
    %PXOMPBE.BOBHFS
    .FEJB1MBZCBDL
    1FSNJTTJPOT
    /PUJDBUJPOT
    4IBSJOH
    4MJDFT
    "OJNBUJPO5SBOTJUJPOT
    "VUP 578FBS
    &NPKJ
    'SBHNFOU
    -BZPVU
    1BMFUUF
    "QQ$PNQBU
    "OESPJE,59
    .VMUJEFY
    5FTU

    View Slide

  18. -JGFDZDMFT
    -JWF%BUB
    7JFX.PEFM
    3PPN
    1BHJOH
    %BUB#JOEJOH
    /BWJHBUJPO
    8PSL.BOBHFS

    View Slide

  19. Lifcycle problems

    View Slide

  20. In early days

    View Slide

  21. Steve Pomeroy https://github.com/xxv/android-lifecycle CC-BY-SA 4.0
    Today

    View Slide

  22. LifecycleObserver

    View Slide

  23. Android System
    NetworkReceiver Network state
    Foo Activity
    observe
    observe
    notify
    notify
    state changed

    View Slide

  24. class NetworkReceiver(val listener : (NetworkInfo) -> Unit) : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
    val con = context.getSystemService(ConnectivityManager::class.java)
    listener(con.activeNetworkInfo)
    }
    }

    View Slide

  25. class NetworkReceiver(val listener : (NetworkInfo) -> Unit) : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
    val con = context.getSystemService(ConnectivityManager::class.java)
    listener(con.activeNetworkInfo)
    }
    }

    View Slide

  26. class NetworkReceiver(val listener : (NetworkInfo) -> Unit) : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
    val con = context.getSystemService(ConnectivityManager::class.java)
    listener(con.activeNetworkInfo)
    }
    }

    View Slide

  27. class MainActivity : AppCompatActivity() {
    private lateinit var networkReceiver : NetworkReceiver
    override fun onCreate(...) {
    networkReceiver = NetworkReceiver { // do something }
    val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    registerReceiver(networkReceiver, filter)
    }
    override fun onDestroy() {
    unregisterReceiver(networkReceiver)
    }
    }

    View Slide

  28. class MainActivity : AppCompatActivity() {
    private lateinit var networkReceiver : NetworkReceiver
    override fun onCreate(...) {
    networkReceiver = NetworkReceiver { // do something }
    val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    registerReceiver(networkReceiver, filter)
    }
    override fun onDestroy() {
    unregisterReceiver(networkReceiver)
    }
    }

    View Slide

  29. class MainActivity : AppCompatActivity() {
    private lateinit var networkReceiver : NetworkReceiver
    override fun onCreate(...) {
    networkReceiver = NetworkReceiver { // do something }
    val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    registerReceiver(networkReceiver, filter)
    }
    override fun onDestroy() {
    unregisterReceiver(networkReceiver)
    }
    }

    View Slide

  30. class NetworkObserver(val owner : LifecycleOwner,
    private val context: Context,
    private val listener: (NetworkInfo) -> Unit)
    : LifecycleObserver {
    private val receiver = object : BroadcastReceiver() {
    ...
    }
    }

    View Slide

  31. class NetworkObserver(val owner : LifecycleOwner,
    private val context: Context,
    private val listener: (NetworkInfo) -> Unit)
    : LifecycleObserver {
    init {
    owner.lifecycle.addObserver(this)
    }
    private val receiver = object : BroadcastReceiver() {
    ...
    }
    }

    View Slide

  32. ...
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun register() {
    val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
    context.registerReceiver(receiver, filter)
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun unregister() {
    context.unregisterReceiver(receiver)
    }
    }

    View Slide

  33. class MainActivity : AppCompatActivity() {
    override fun onCreate(...) {
    NetworkObserver(this, this) {
    // do something
    }
    }
    }

    View Slide

  34. Observer Pattern
    vs
    Pub-Sub Pattern

    View Slide

  35. <>
    Subject

    View Slide

  36. <>
    Subject
    ConcreteSubject ConcreteSubject

    View Slide

  37. <>
    Subject
    ConcreteSubject ConcreteSubject
    <>
    Observer
    ConcreteObserve
    r
    ConcreteObserve
    r
    observe

    View Slide

  38. <>
    Subject
    ConcreteSubject ConcreteSubject
    <>
    Observer
    ConcreteObserve
    r
    ConcreteObserve
    r
    event
    notify

    View Slide

  39. View Slide

  40. View Slide

  41. View Slide

  42. View Slide

  43. LiveData

    View Slide

  44. View Slide

  45. Activity#0
    created
    onCreate
    onStart
    onResume
    onPause
    onStop
    onDestroy
    Device
    rotated
    Activity#1
    created
    Exception
    Call Web API

    View Slide

  46. LiveData
    addObserver

    View Slide

  47. LiveData
    Observer
    value

    View Slide

  48. LiveData
    Observer
    Lifecycle
    Owner

    View Slide

  49. Lifecycle
    Owner
    LiveData
    LifecycleBoundObserver
    Observer
    addObserver
    addObserver dispatch events
    active
    onChanged
    LiveData

    View Slide

  50. Lifecycle
    Owner
    LiveData
    LifecycleBoundObserver
    Observer
    addObserver
    addObserver dispatch events
    inactive
    onChanged
    LiveData

    View Slide

  51. Lifecycle
    Owner
    LiveData
    LifecycleBoundObserver
    Observer
    removeObserver
    addObserver dispatch events
    destroyed
    onChanged

    View Slide

  52. object CatRepository {
    private val _cat = MutableLiveData()
    fun loadCat(catId : Int) : LiveData {
    fetch(catId) { newCat -> _cat.postValue(newCat) }
    return _cat
    }
    }

    View Slide

  53. class CatActivity : AppCompatActivity() {
    override fun onCreate(...) {
    val catId = intent.getIntExtra("cat_id")
    CatRepository.loadCat(catId).observe(this,
    Observer { cat -> showCat(cat)})
    }
    }

    View Slide

  54. class CatActivity : AppCompatActivity() {
    override fun onCreate(...) {
    ...
    val relatedCatsModule = RelatedCatsModuleAdapter { clicked ->
    val intent = Intent(this, CatActivity::class.java)
    intent.putExtra("cat_id", clicked.id)
    startActivity(intent)
    }
    }
    }

    View Slide

  55. ViewModels

    View Slide

  56. View Slide

  57. Activity#0
    created
    onCreate
    onStart
    onResume
    Call Web API

    View Slide

  58. Activity#0
    created
    onCreate
    onStart
    onResume
    onPause
    onStop
    onDestroy
    Device
    rotated
    Activity#1
    created
    Call Web API
    onCreate
    Call Web API

    View Slide

  59. ViewModel
    Provider
    ViewModel
    Store
    Activity/Fragment
    request
    get
    null
    ViewModel

    View Slide

  60. return
    ViewModel
    Provider
    ViewModel
    Store
    Activity/Fragment
    request
    get
    null
    put
    ViewModel
    ViewModel

    View Slide

  61. ViewModel
    Store
    Activity/Fragment
    ViewModel
    in NonConfigurationInstance

    View Slide

  62. View Slide

  63. public class FragmentActivity extends ComponentActivity ... {
    @Override public final Object onRetainNonConfigurationInstance() {
    ...
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = mViewModelStore;
    nci.fragments = fragments;
    return nci;
    }

    View Slide

  64. public class FragmentActivity extends ComponentActivity ... {
    @Override protected void onCreate(...) {
    ...
    NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {
    mViewModelStore = nc.viewModelStore;
    }

    View Slide

  65. View Slide

  66. Repository
    Model
    Repository

    View Slide

  67. Repository
    Model
    Repository
    Activity / Fragment

    View Slide

  68. Repository
    Model

    View Slide

  69. private val _cat = MutableLiveData>()
    fun updateCat(new: Cat) {
    val currentCats = _cat.value ?: return
    val updatedCats = currentCats.toMutableList()
    .map { old -> if(old.id == new.id) new else old }
    _cat.postValue(updatedCats)
    // update storage and web service
    ...
    }

    View Slide

  70. private val _cat = MutableLiveData>()
    fun updateCat(new: Cat) {
    val currentCats = _cat.value ?: return
    val updatedCats = currentCats.toMutableList()
    .map { old -> if(old.id == new.id) new else old }
    _cat.postValue(updatedCats)
    // update storage and web service
    ...
    }

    View Slide

  71. private val _cat = MutableLiveData>()
    fun updateCat(new: Cat) {
    val currentCats = _cat.value ?: return
    val updatedCats = currentCats.toMutableList()
    .map { old -> if(old.id == new.id) new else old }
    _cat.postValue(updatedCats)
    // update storage and web service
    ...
    }

    View Slide

  72. @Entity
    data class Cat(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val name: String,
    val age: Int,
    val description: String,
    val loved: Boolean
    )

    View Slide

  73. @Dao
    interface CatDao {
    @Query("SELECT * from Cat")
    fun loadCats() : LiveData>
    @Update
    fun update(cat: Cat)
    }

    View Slide

  74. @Database(entities = [Cat::class], version = 1)
    abstract class CatDatabase : RoomDatabase() {
    abstract fun catDao() : CatDao
    }

    View Slide

  75. fun getCatDatabase(context: Context) =
    Room.databaseBuilder(context, CatDatabase::class.java, "catDB").build()

    View Slide

  76. fun updateCat(new: Cat) {
    // update logic here
    catDao.updateCat(new)
    catService.updateData(new)
    }

    View Slide

  77. Cat Database
    Cat table
    room_master_table
    Id, identity_hash

    View Slide

  78. Cat Database
    Cat table
    room_master_table
    Id, identity_hash
    room_table_modification_log
    InvalidationTracker
    Updated?
    Version, table_id
    onInvalidated
    Observer
    trigger
    Oh, yes!

    View Slide

  79. Cat Database
    Cat table
    room_master_table
    Id, identity_hash
    room_table_modification_log
    InvalidationTracker
    Version, table_id
    Observer
    ComputeLiveDat
    a
    addObserver
    query
    Cat Dao

    View Slide

  80. Cat Database
    Cat table
    room_master_table
    Id, identity_hash
    room_table_modification_log
    InvalidationTracker
    Version, table_id
    Observer
    Cat Dao
    ComputeLiveDat
    a
    addObserver
    query
    onInvalidated

    View Slide

  81. Why use Paging library?

    View Slide

  82. Repository
    ViewModel
    Activity /
    Fragment
    What do
    I display?
    I need cats
    Give us
    ALL Cats
    OK,
    1,000,000
    cats here.
    Here you are
    Show this
    1,000,000
    cats
    ¯\_(π)_/¯

    View Slide

  83. PagedList DataSource

    View Slide

  84. PagedList DataSource

    View Slide

  85. PagedList DataSource
    DataSource.Factory

    View Slide

  86. PagedList DataSource
    DataSource.Factory
    invalidate

    View Slide

  87. PagedList DataSource
    DataSource.Factory

    View Slide

  88. View ViewModel Repository
    DataSource.Factory
    LiveData>
    Room
    LivePagedListBuilder

    View Slide

  89. View
    Observer
    ViewModel Repository
    DataSource.Factory
    LiveData>
    Room
    LivePagedListBuilder
    LivePagedListBuilder
    DataSource.Factory

    View Slide

  90. View ViewModel Repository
    DataSource.Factory
    LiveData>
    PagedListAdapter
    Room
    Observer LivePagedListBuilder
    AsyncPagedListDiffer

    View Slide

  91. View ViewModel Repository
    DataSource.Factory
    LiveData>
    PagedListAdapter
    Room
    Observer LivePagedListBuilder
    AsyncPagedListDiffer

    View Slide

  92. public abstract class PagedListAdapter ... {
    final AsyncPagedListDiffer mDiffer;
    @Nullable protected T getItem(int position) {
    return mDiffer.getItem(position);
    }
    }

    View Slide

  93. public class AsyncPagedListDiffer {
    ...
    public T getItem(int index) {
    ...
    mPagedList.loadAround(index);
    return mPagedList.get(index);
    }
    }

    View Slide

  94. public abstract class PagedList extends AbstractList {
    ...
    public void loadAround(int index) {
    ...
    loadAroundInternal(index);
    ...
    }
    }

    View Slide

  95. class ContiguousPagedList extends PagedList ... {
    protected void loadAroundInternal(int index) {
    int appendItems = getAppendItemsRequested(...);
    ...
    mAppendItemsRequested = Math.max(...);
    if (mAppendItemsRequested > 0) {
    scheduleAppend();
    }
    }

    View Slide

  96. Summary

    View Slide