SlideShare a Scribd company logo
David Vávra: Firebase + Kotlin + RX + MVP
David Vávra: Firebase + Kotlin + RX + MVP
Firebase + Kotlin + Rx + MVP
David Vávra
@vavradav, +David Vávra, medium.com/@david.vavra
About me
Founder&CEO at
Android and backend hacker of Settle Up
Google Developer Expert for
Organizer at GDG Prague
Settle Up
Redesigned Settle Up
Architecture choices
Firebase
Realtime
Database
Own server Realm
Kotlin Java
MVP MVVM
Challenges & how we solved them
How to structure
data in Firebase
Realtime
Database?
{
"transactions": {
"group_id_1": {
"expense_id_1": {
...
}
}
},
"groups": {
"group_id_1": {
"name": "India trip",
...
}
},
"permissions": {
"group_id_1": {
"user_id_1": {
"level" : 30
}
}
},
"usersGroups": {
"user_id_1": {
"group_id_1": true,
"group_id_2": true
}
}
}
http://bit.ly/firebasestructure
How can presenter survive configuration changes
abstract class BaseFragment<P : Presenter<V>, V : MvpView> : Fragment(), LoaderManager.LoaderCallbacks<P> {
private var mPresenter: P? = null
override fun onActivityCreated(savedInstanceState: Bundle?) {
loaderManager.initLoader(PRESENTER_LOADER_ID, Bundle(), this)
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<P>? {
return PresenterLoader(activity, getPresenterFactory())
}
override fun onLoadFinished(loader: Loader<P>, presenter: P) {
mPresenter = presenter
}
override fun onResume() {
mPresenter?.attachView(this as V)
}
override fun onPause() {
mPresenter?.detachView()
}
}
http://bit.ly/presenterrotation
How can presenter survive configuration changes
class PresenterLoader<T : Presenter<out MvpView>>(context: Context, val factory: PresenterFactory<T>) : Loader<T>(context) {
private var presenter: T? = null
override fun onStartLoading() {
if (presenter != null) {
deliverResult(presenter)
} else {
forceLoad()
}
}
override fun onForceLoad() {
presenter = mFactory.create()
presenter?.onCreatedByLoader()
deliverResult(presenter)
}
override fun onReset() {
presenter?.onDestroyedByLoader()
presenter = null
}
}
http://bit.ly/presenterrotation
How to coordinate multiple async calls to Firebase Realtime Database
fun observe(query: DatabaseQuery): Observable<DataSnapshot> {
return Observable.fromAsync<DataSnapshot>({
val listener = query.addValueEventListener(object : ValueEventListener {
override fun onCancelled(databaseError: DatabaseError) {
it.onError(RuntimeException(databaseError.message))
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
it.onNext(dataSnapshot)
}
})
it.setCancellation { query.removeEventListener(listener) }
}, AsyncEmitter.BackpressureMode.BUFFER)
}
http://bit.ly/rxfirebase
How to coordinate multiple async calls to Firebase Realtime Database
object DatabaseRead {
fun getUserGroupColor(groupId: String): Observable<String> {
return ObjectQuery().apply { path = "userGroups/${Auth.getUserId()}/$groupId/color" }
.observe()
.toPrimitiveObservable(String::class.java)
}
fun getMember(groupId: String, memberId: String): Observable<Member> {
return ObjectQuery().apply { path = "members/$groupId/$memberId" }
.observe()
.toObjectObservable(Member::class.java)
}
}
How to coordinate multiple async calls to Firebase Realtime Database
private fun <T> load(observable: Observable<T>, displayToView: (T) -> Unit) {
val data = PresenterData(observable, displayToView)
data.subscription = data.observable.subscribe({
data.cachedValue = it
if (isViewAttached) {
data.displayToView(it)
}
}, {
showError(it)
})
mDataList.add(data)
}
How to coordinate multiple async calls to Firebase Realtime Database
fun loadMultiple(observables: List<Observable<out Any>>, displayToView: (Array<Any>) -> Unit) {
val data = PresenterMultipleData(observables, displayToView)
Observable.combineLatest(observables, {
it
}).subscribe({
data.cachedValue = it
if (isViewAttached) {
data.displayToView(it)
}
}, {
showError(it)
})
mMultipleDataList.add(data)
}
Concrete example - Member detail screen
{
"members": {
"group_id_2": {
"member_id_1": {
"bankAccount": "532224564654/0100",
"defaultWeight": "1",
"name": "David",
"photoUrl": "https://lh3.googleusercontent.com/...jpg"
}
}
},
"userGroups": {
"user_id_1": {
"group_id_2": {
"color": "#00BCD4",
"member": "member_id_1"
}
}
}
Concrete example - Member detail screen
class MemberDetailPresenter(val groupId: String, val memberId: String) : BasePresenter<MemberDetailMvpView>() {
override fun onCreatedByLoader() {
loadOnce(DatabaseRead.getUserGroupColor(groupId), {
getView().setGroupColor(Color.parseColor(it))
})
loadMultiple(listOf(DatabaseRead.getMember(groupId, memberId), DatabaseRead.getUserMember(groupId)) {
val member = it[0] as Member
val userMember = it[1] as String?
getView().setMember(member, member.id == userMember)
})
}
}
Concrete example - Member detail screen
class MemberDetailActivity : BaseActivity<MemberDetailPresenter, MemberDetailMvpView>(), MemberDetailMvpView {
override fun getLayoutRes(): Int {
return R.layout.activity_member_detail
}
override fun getPresenterFactory(): PresenterFactory<MemberDetailPresenter> {
return MemberDetailPresenter.Factory(getGroupId(), getMemberId())
}
override fun setMember(member: Member, thisIsMe: Boolean) {
vName.setText(member.name)
vThisIsMe.isChecked = thisIsMe
}
override fun setGroupColor(color: Int) {
vHeader.setBackgroundColor(color)
}
}
How does Firebase pricing affect
monetization?
Realtime Database:
$5/stored GB monthly
Storage:
$0.026/stored GB monthly
Our monetization:
Freemium
● Subscription
● Or free app with video ads
http://bit.ly/firebasepricing
Windows support?
https://github.com/step-up-labs/firebase-database-dotnet
https://github.com/step-up-labs/firebase-authentication-dotnet
https://github.com/step-up-labs/firebase-storage-dotnet
TL;DR
Firebase is great
Build new apps in Kotlin
Use MVP architecture, Presenter should survive orientation change with Loader
RxJava is great for combining multiple async calls to Firebase
Think about database structure and monetization before you start building
Q&A
Follow me:
twitter.com/vavradav
medium.com/@david.vavra

More Related Content

PDF
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
PPTX
Operational Intelligence with MongoDB Webinar
PDF
ABCD firebase
PDF
MongoDB World 2018: Using Change Streams to Keep Up with Your Data
PDF
Xa transactions over camel routes
PDF
FleetDB: A Schema-Free Database in Clojure
PPTX
NoSQL in SQL - Lior Altarescu
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
Operational Intelligence with MongoDB Webinar
ABCD firebase
MongoDB World 2018: Using Change Streams to Keep Up with Your Data
Xa transactions over camel routes
FleetDB: A Schema-Free Database in Clojure
NoSQL in SQL - Lior Altarescu

What's hot (12)

PPTX
Working with NoSQL in a SQL Database (XDevApi)
PDF
FleetDB A Schema-Free Database in Clojure
PPTX
MongoDB World 2018: Time for a Change Stream - Using MongoDB Change Streams t...
PDF
Jan Lehnardt Couch Db In A Real World Setting
PPTX
1403 app dev series - session 5 - analytics
PDF
Akka with Scala
PDF
MongoDB .local Munich 2019: Best Practices for Working with IoT and Time-seri...
PDF
Easy Scaling with Open Source Data Structures, by Talip Ozturk
PPTX
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
PDF
Heroku Postgres Cloud Database Webinar
PDF
Composable caching
PDF
MySQL flexible schema and JSON for Internet of Things
Working with NoSQL in a SQL Database (XDevApi)
FleetDB A Schema-Free Database in Clojure
MongoDB World 2018: Time for a Change Stream - Using MongoDB Change Streams t...
Jan Lehnardt Couch Db In A Real World Setting
1403 app dev series - session 5 - analytics
Akka with Scala
MongoDB .local Munich 2019: Best Practices for Working with IoT and Time-seri...
Easy Scaling with Open Source Data Structures, by Talip Ozturk
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Heroku Postgres Cloud Database Webinar
Composable caching
MySQL flexible schema and JSON for Internet of Things
Ad

Similar to David Vávra: Firebase + Kotlin + RX + MVP (20)

PPTX
Big Data for each one of us
PDF
REST more with json-api and fractal
PDF
Overview of The Scala Based Lift Web Framework
PDF
Scala based Lift Framework
PDF
Overview Of Lift Framework
PDF
mobl presentation @ IHomer
PDF
Kitura Todolist tutorial
PPTX
LiveOps para games usando o Firebase
PPTX
MongoDB World 2018: Keynote
PDF
Advanced #2 networking
KEY
Scala on Your Phone
PDF
mobl - model-driven engineering lecture
PDF
Reduxing like a pro
PDF
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
PDF
Spark Cassandra Connector: Past, Present, and Future
PDF
DataStax: Spark Cassandra Connector - Past, Present and Future
PDF
PPTX
Progressive Enhancment with Rails and React
PPTX
Knockoutjs UG meeting presentation
PDF
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
Big Data for each one of us
REST more with json-api and fractal
Overview of The Scala Based Lift Web Framework
Scala based Lift Framework
Overview Of Lift Framework
mobl presentation @ IHomer
Kitura Todolist tutorial
LiveOps para games usando o Firebase
MongoDB World 2018: Keynote
Advanced #2 networking
Scala on Your Phone
mobl - model-driven engineering lecture
Reduxing like a pro
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
Spark Cassandra Connector: Past, Present, and Future
DataStax: Spark Cassandra Connector - Past, Present and Future
Progressive Enhancment with Rails and React
Knockoutjs UG meeting presentation
Camunda BPM 7.2: Tasklist and Javascript Forms SDK (English)
Ad

More from mdevtalk (20)

PDF
Jan Čislinský: Seznámení se Sourcery aneb Základy metaprogramování ve Swiftu
PDF
Jarda Machaň: Proč je dobré míti Developer Evangelistu
PDF
Pavel Cvetler: Jeden kód, co vládne všem? Žádný problém pro Android i iOS
PDF
Anastasiia Vixentael: 10 things you need to know before implementing cryptogr...
PDF
Michal Havryluk: How To Speed Up Android Gradle Builds
PDF
Vladislav Iliushin: Dark side of IoT
PDF
Georgiy Shur: Bring onboarding to life
PDF
David Bilík: Anko – modern way to build your layouts?
PDF
Maxim Zaks: Deep dive into data serialisation
PDF
Nikita Tuk: Handling background processes in iOS: problems & solutions
PDF
Milan Oulehla: Bezpečnost mobilních aplikací na Androidu
PDF
Tomáš Kohout: Jak zrychlit iOS vývoj pomocí Swift playgoundů
PDF
Adam Šimek: Optimalizace skrolování, RecyclerView
PDF
Paul Lammertsma: Account manager & sync
PDF
Charles Du: Introduction to Mobile UX Design
PDF
Honza Dvorský: Swift Package Manager
PDF
David Bureš - Xamarin, IoT a Azure
PDF
Dominik Veselý - Vše co jste kdy chtěli vědět o CI a báli jste se zeptat
PDF
Jiří Dutkevič: Ochrana citlivých dat v iOS
PDF
Petr Dvořák: Push notifikace ve velkém
Jan Čislinský: Seznámení se Sourcery aneb Základy metaprogramování ve Swiftu
Jarda Machaň: Proč je dobré míti Developer Evangelistu
Pavel Cvetler: Jeden kód, co vládne všem? Žádný problém pro Android i iOS
Anastasiia Vixentael: 10 things you need to know before implementing cryptogr...
Michal Havryluk: How To Speed Up Android Gradle Builds
Vladislav Iliushin: Dark side of IoT
Georgiy Shur: Bring onboarding to life
David Bilík: Anko – modern way to build your layouts?
Maxim Zaks: Deep dive into data serialisation
Nikita Tuk: Handling background processes in iOS: problems & solutions
Milan Oulehla: Bezpečnost mobilních aplikací na Androidu
Tomáš Kohout: Jak zrychlit iOS vývoj pomocí Swift playgoundů
Adam Šimek: Optimalizace skrolování, RecyclerView
Paul Lammertsma: Account manager & sync
Charles Du: Introduction to Mobile UX Design
Honza Dvorský: Swift Package Manager
David Bureš - Xamarin, IoT a Azure
Dominik Veselý - Vše co jste kdy chtěli vědět o CI a báli jste se zeptat
Jiří Dutkevič: Ochrana citlivých dat v iOS
Petr Dvořák: Push notifikace ve velkém

Recently uploaded (10)

DOC
Camb毕业证学历认证,格罗斯泰斯特主教大学毕业证仿冒文凭毕业证
PDF
Best 4 Sites for Buy Verified Cash App Accounts – BTC Only.pdf
DOC
NIU毕业证学历认证,阿比林基督大学毕业证留学生学历
PDF
2025 Guide to Buy Verified Cash App Accounts You Can Trust.pdf
PDF
Kids, Screens & Emotional Development by Meenakshi Khakat
PPTX
ASMS Telecommunication company Profile
DOC
SIUE毕业证学历认证,阿祖萨太平洋大学毕业证学位证书复制
PPTX
Introduction to Packet Tracer Course Overview - Aug 21 (1).pptx
PDF
Lesson 13- HEREDITY _ pedSAWEREGFVCXZDSASEWFigree.pdf
PPTX
Social Media People PowerPoint Templates.pptx
Camb毕业证学历认证,格罗斯泰斯特主教大学毕业证仿冒文凭毕业证
Best 4 Sites for Buy Verified Cash App Accounts – BTC Only.pdf
NIU毕业证学历认证,阿比林基督大学毕业证留学生学历
2025 Guide to Buy Verified Cash App Accounts You Can Trust.pdf
Kids, Screens & Emotional Development by Meenakshi Khakat
ASMS Telecommunication company Profile
SIUE毕业证学历认证,阿祖萨太平洋大学毕业证学位证书复制
Introduction to Packet Tracer Course Overview - Aug 21 (1).pptx
Lesson 13- HEREDITY _ pedSAWEREGFVCXZDSASEWFigree.pdf
Social Media People PowerPoint Templates.pptx

David Vávra: Firebase + Kotlin + RX + MVP

  • 3. Firebase + Kotlin + Rx + MVP David Vávra @vavradav, +David Vávra, medium.com/@david.vavra
  • 4. About me Founder&CEO at Android and backend hacker of Settle Up Google Developer Expert for Organizer at GDG Prague
  • 11. Challenges & how we solved them
  • 12. How to structure data in Firebase Realtime Database? { "transactions": { "group_id_1": { "expense_id_1": { ... } } }, "groups": { "group_id_1": { "name": "India trip", ... } }, "permissions": { "group_id_1": { "user_id_1": { "level" : 30 } } }, "usersGroups": { "user_id_1": { "group_id_1": true, "group_id_2": true } } } http://bit.ly/firebasestructure
  • 13. How can presenter survive configuration changes abstract class BaseFragment<P : Presenter<V>, V : MvpView> : Fragment(), LoaderManager.LoaderCallbacks<P> { private var mPresenter: P? = null override fun onActivityCreated(savedInstanceState: Bundle?) { loaderManager.initLoader(PRESENTER_LOADER_ID, Bundle(), this) } override fun onCreateLoader(id: Int, args: Bundle): Loader<P>? { return PresenterLoader(activity, getPresenterFactory()) } override fun onLoadFinished(loader: Loader<P>, presenter: P) { mPresenter = presenter } override fun onResume() { mPresenter?.attachView(this as V) } override fun onPause() { mPresenter?.detachView() } } http://bit.ly/presenterrotation
  • 14. How can presenter survive configuration changes class PresenterLoader<T : Presenter<out MvpView>>(context: Context, val factory: PresenterFactory<T>) : Loader<T>(context) { private var presenter: T? = null override fun onStartLoading() { if (presenter != null) { deliverResult(presenter) } else { forceLoad() } } override fun onForceLoad() { presenter = mFactory.create() presenter?.onCreatedByLoader() deliverResult(presenter) } override fun onReset() { presenter?.onDestroyedByLoader() presenter = null } } http://bit.ly/presenterrotation
  • 15. How to coordinate multiple async calls to Firebase Realtime Database fun observe(query: DatabaseQuery): Observable<DataSnapshot> { return Observable.fromAsync<DataSnapshot>({ val listener = query.addValueEventListener(object : ValueEventListener { override fun onCancelled(databaseError: DatabaseError) { it.onError(RuntimeException(databaseError.message)) } override fun onDataChange(dataSnapshot: DataSnapshot) { it.onNext(dataSnapshot) } }) it.setCancellation { query.removeEventListener(listener) } }, AsyncEmitter.BackpressureMode.BUFFER) } http://bit.ly/rxfirebase
  • 16. How to coordinate multiple async calls to Firebase Realtime Database object DatabaseRead { fun getUserGroupColor(groupId: String): Observable<String> { return ObjectQuery().apply { path = "userGroups/${Auth.getUserId()}/$groupId/color" } .observe() .toPrimitiveObservable(String::class.java) } fun getMember(groupId: String, memberId: String): Observable<Member> { return ObjectQuery().apply { path = "members/$groupId/$memberId" } .observe() .toObjectObservable(Member::class.java) } }
  • 17. How to coordinate multiple async calls to Firebase Realtime Database private fun <T> load(observable: Observable<T>, displayToView: (T) -> Unit) { val data = PresenterData(observable, displayToView) data.subscription = data.observable.subscribe({ data.cachedValue = it if (isViewAttached) { data.displayToView(it) } }, { showError(it) }) mDataList.add(data) }
  • 18. How to coordinate multiple async calls to Firebase Realtime Database fun loadMultiple(observables: List<Observable<out Any>>, displayToView: (Array<Any>) -> Unit) { val data = PresenterMultipleData(observables, displayToView) Observable.combineLatest(observables, { it }).subscribe({ data.cachedValue = it if (isViewAttached) { data.displayToView(it) } }, { showError(it) }) mMultipleDataList.add(data) }
  • 19. Concrete example - Member detail screen { "members": { "group_id_2": { "member_id_1": { "bankAccount": "532224564654/0100", "defaultWeight": "1", "name": "David", "photoUrl": "https://lh3.googleusercontent.com/...jpg" } } }, "userGroups": { "user_id_1": { "group_id_2": { "color": "#00BCD4", "member": "member_id_1" } } }
  • 20. Concrete example - Member detail screen class MemberDetailPresenter(val groupId: String, val memberId: String) : BasePresenter<MemberDetailMvpView>() { override fun onCreatedByLoader() { loadOnce(DatabaseRead.getUserGroupColor(groupId), { getView().setGroupColor(Color.parseColor(it)) }) loadMultiple(listOf(DatabaseRead.getMember(groupId, memberId), DatabaseRead.getUserMember(groupId)) { val member = it[0] as Member val userMember = it[1] as String? getView().setMember(member, member.id == userMember) }) } }
  • 21. Concrete example - Member detail screen class MemberDetailActivity : BaseActivity<MemberDetailPresenter, MemberDetailMvpView>(), MemberDetailMvpView { override fun getLayoutRes(): Int { return R.layout.activity_member_detail } override fun getPresenterFactory(): PresenterFactory<MemberDetailPresenter> { return MemberDetailPresenter.Factory(getGroupId(), getMemberId()) } override fun setMember(member: Member, thisIsMe: Boolean) { vName.setText(member.name) vThisIsMe.isChecked = thisIsMe } override fun setGroupColor(color: Int) { vHeader.setBackgroundColor(color) } }
  • 22. How does Firebase pricing affect monetization? Realtime Database: $5/stored GB monthly Storage: $0.026/stored GB monthly Our monetization: Freemium ● Subscription ● Or free app with video ads http://bit.ly/firebasepricing
  • 24. TL;DR Firebase is great Build new apps in Kotlin Use MVP architecture, Presenter should survive orientation change with Loader RxJava is great for combining multiple async calls to Firebase Think about database structure and monetization before you start building