-
Notifications
You must be signed in to change notification settings - Fork 305
StoreRoom #338
StoreRoom #338
Changes from 4 commits
7c74b34
67a353a
907d230
395fd42
7c669f9
1a77719
27234de
5804e19
b1a7b94
39eab81
c1b7ead
8ee3d09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
apply plugin: 'com.android.application' | ||
apply plugin: 'kotlin-android' | ||
apply plugin: 'com.getkeepsafe.dexcount' | ||
|
||
apply plugin: 'kotlin-kapt' | ||
android { | ||
compileSdkVersion versions.compileSdk | ||
buildToolsVersion versions.buildTools | ||
|
@@ -31,6 +32,7 @@ android { | |
exclude 'META-INF/rxjava.properties' | ||
} | ||
} | ||
def room_version = "1.1.0" // or, for latest rc, use "1.1.1-rc1" | ||
|
||
dependencies { | ||
|
||
|
@@ -48,9 +50,25 @@ dependencies { | |
annotationProcessor libraries.immutablesValue // <-- for annotation processor | ||
compileOnly libraries.immutablesValue // <-- for annotation API | ||
compileOnly libraries.immutablesGson // for annotations | ||
implementation 'com.nytimes.android:store3:3.0.1' | ||
implementation 'com.nytimes.android:cache3:3.0.1' | ||
implementation 'com.nytimes.android:middleware3:3.0.1' | ||
implementation 'com.nytimes.android:filesystem3:3.0.1' | ||
implementation project(':store') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might need to flip before checking in.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do once I can push the new snapshot thanks! |
||
implementation project(':cache') | ||
implementation project(':middleware') | ||
implementation project(':filesystem') | ||
implementation libraries.rxAndroid2 | ||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | ||
|
||
implementation "android.arch.persistence.room:runtime:$room_version" | ||
annotationProcessor "android.arch.persistence.room:compiler:$room_version" | ||
kapt "android.arch.persistence.room:compiler:$room_version" | ||
|
||
// androidTestImplementation "android.arch.persistence.room:testing:$room_version" | ||
// optional - RxJava support for Room | ||
implementation "android.arch.persistence.room:rxjava2:$room_version" | ||
} | ||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
configurations.all { | ||
resolutionStrategy.force 'com.android.support:support-v4:26.1.0' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems we're still using support lib v26.1.0 while there is latest one v27.1.1. Any plan to upgrade? |
||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package com.nytimes.android.sample | ||
|
||
import android.app.Application | ||
import android.content.Context | ||
import com.google.gson.Gson | ||
import com.google.gson.GsonBuilder | ||
import com.nytimes.android.external.fs3.SourcePersisterFactory | ||
import com.nytimes.android.external.store3.base.Fetcher | ||
import com.nytimes.android.external.store3.base.Persister | ||
import com.nytimes.android.external.store3.base.impl.BarCode | ||
import com.nytimes.android.external.store3.base.impl.MemoryPolicy | ||
import com.nytimes.android.external.store3.base.impl.Store | ||
import com.nytimes.android.external.store3.base.impl.StoreBuilder | ||
import com.nytimes.android.external.store3.middleware.GsonParserFactory | ||
import com.nytimes.android.sample.data.model.GsonAdaptersModel | ||
import com.nytimes.android.sample.data.model.RedditData | ||
import com.nytimes.android.sample.data.remote.Api | ||
import io.reactivex.Observable | ||
import io.reactivex.Single | ||
import io.reactivex.android.schedulers.AndroidSchedulers | ||
import io.reactivex.schedulers.Schedulers | ||
import okio.BufferedSource | ||
import retrofit2.Retrofit | ||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory | ||
import retrofit2.converter.gson.GsonConverterFactory | ||
import java.io.IOException | ||
import java.util.concurrent.TimeUnit | ||
|
||
class SampleApp : Application() { | ||
|
||
var nonPersistedStore: Store<RedditData, BarCode>? = null | ||
var persistedStore: Store<RedditData, BarCode>? =null | ||
private var persister: Persister<BufferedSource, BarCode>? =null | ||
|
||
override fun onCreate() { | ||
super.onCreate() | ||
appContext = this | ||
|
||
initPersister(); | ||
nonPersistedStore = provideRedditStore(); | ||
persistedStore=providePersistedRedditStore(); | ||
RoomSample() | ||
|
||
|
||
} | ||
|
||
private fun RoomSample() { | ||
var foo = store.get("") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see SampleRoomStore.kt for the implementation of this store, biggest takeaway is the ability to treat each store subscription as an endless stream backed by a Room Query. Now anytime you subscribe to |
||
.subscribeOn(Schedulers.io()) | ||
.observeOn(AndroidSchedulers.mainThread()) | ||
.subscribe({ strings1 -> val success = strings1 != null }) { throwable -> throwable.stackTrace } | ||
|
||
foo = Observable.timer(15, TimeUnit.SECONDS) | ||
.subscribe { again() } | ||
} | ||
|
||
private fun again() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change to more descriptive name? |
||
val bar = store.fetch("") | ||
.subscribeOn(Schedulers.io()) | ||
.observeOn(AndroidSchedulers.mainThread()) | ||
.subscribe({ strings1 -> val success = strings1 != null }) { throwable -> throwable.stackTrace } | ||
} | ||
|
||
private fun initPersister() { | ||
try { | ||
persister = newPersister() | ||
} catch (exception: IOException) { | ||
throw RuntimeException(exception) | ||
} | ||
|
||
} | ||
|
||
/** | ||
* Provides a Store which only retains RedditData for 10 seconds in memory. | ||
*/ | ||
private fun provideRedditStore(): Store<RedditData, BarCode> { | ||
return StoreBuilder.barcode<RedditData>() | ||
.fetcher { barCode -> provideRetrofit().fetchSubreddit(barCode.key, "10") } | ||
.memoryPolicy( | ||
MemoryPolicy | ||
.builder() | ||
.setExpireAfterWrite(10) | ||
.setExpireAfterTimeUnit(TimeUnit.SECONDS) | ||
.build() | ||
) | ||
.open() | ||
} | ||
|
||
/** | ||
* Provides a Store which will persist RedditData to the cache, and use Gson to parse the JSON | ||
* that comes back from the network into RedditData. | ||
*/ | ||
private fun providePersistedRedditStore(): Store<RedditData, BarCode> { | ||
return StoreBuilder.parsedWithKey<BarCode, BufferedSource, RedditData>() | ||
.fetcher(Fetcher<BufferedSource, BarCode> { this.fetcher(it) }) | ||
.persister(newPersister()) | ||
.parser(GsonParserFactory.createSourceParser(provideGson(), RedditData::class.java)) | ||
.open() | ||
} | ||
|
||
/** | ||
* Returns a new Persister with the cache as the root. | ||
*/ | ||
@Throws(IOException::class) | ||
private fun newPersister(): Persister<BufferedSource, BarCode> { | ||
return SourcePersisterFactory.create(this.cacheDir) | ||
} | ||
|
||
/** | ||
* Returns a "fetcher" which will retrieve new data from the network. | ||
*/ | ||
private fun fetcher(barCode: BarCode): Single<BufferedSource> { | ||
return provideRetrofit().fetchSubredditForPersister(barCode.key, "10") | ||
.map({ it.source() }) | ||
} | ||
|
||
private fun provideRetrofit(): Api { | ||
return Retrofit.Builder() | ||
.baseUrl("http://reddit.com/") | ||
.addConverterFactory(GsonConverterFactory.create(provideGson())) | ||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) | ||
.validateEagerly(BuildConfig.DEBUG) // Fail early: check Retrofit configuration at creation time in Debug build. | ||
.build() | ||
.create(Api::class.java) | ||
} | ||
|
||
internal fun provideGson(): Gson { | ||
return GsonBuilder() | ||
.registerTypeAdapterFactory(GsonAdaptersModel()) | ||
.create() | ||
} | ||
|
||
companion object { | ||
|
||
var appContext: Context? = null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not great, lets avoid having objects create a static reference to themselves? |
||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. format and remove EL for this file.. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.nytimes.android.sample | ||
|
||
import android.arch.persistence.room.Dao | ||
import android.arch.persistence.room.Database | ||
import android.arch.persistence.room.Entity | ||
import android.arch.persistence.room.Insert | ||
import android.arch.persistence.room.PrimaryKey | ||
import android.arch.persistence.room.Query | ||
import android.arch.persistence.room.Room | ||
import android.arch.persistence.room.RoomDatabase | ||
import com.nytimes.android.external.store3.base.Fetcher | ||
import com.nytimes.android.external.store3.base.impl.StalePolicy | ||
import com.nytimes.android.external.store3.base.impl.room.RoomInternalStore | ||
import com.nytimes.android.external.store3.base.room.RoomPersister | ||
import io.reactivex.Flowable | ||
import io.reactivex.Observable | ||
import io.reactivex.Single | ||
|
||
|
||
// File: User.java | ||
@Entity | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple implementation of a RoomDB as a proof of concept |
||
data class User( | ||
@PrimaryKey(autoGenerate = true) var uid: Int = 0, | ||
val name: String, | ||
val lastName: String) | ||
|
||
|
||
// File: UserDao.java | ||
@Dao | ||
interface UserDao { | ||
@Query("SELECT name FROM user") | ||
fun loadAll(): Flowable<List<String>> | ||
|
||
|
||
@Insert | ||
fun insertAll(vararg users: User) | ||
|
||
// @Delete | ||
// fun delete(user: User) | ||
} | ||
|
||
// File: AppDatabase.java | ||
@Database(entities = arrayOf(User::class), version = 1) | ||
abstract class AppDatabase : RoomDatabase() { | ||
abstract fun userDao(): UserDao | ||
} | ||
|
||
val db = Room.databaseBuilder(SampleApp.appContext!!, AppDatabase::class.java, "db").build() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reimplement to avoid using the |
||
|
||
val persister = object : RoomPersister<User, List<String>, String>() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A new persister needed to be created that is exposed as an observable rather than a single. The RoomPersister takes a third param as you can have the freedom to have different queries for reading and writing. In this example writing is always done by adding a single user to the DB while read returns the list of all users. Another use case is writing a User but only reading a part of the user |
||
|
||
override fun read(key: String): Observable<List<String>> { | ||
return db.userDao().loadAll().toObservable() | ||
} | ||
|
||
override fun write(key: String, user: User) { | ||
db.userDao().insertAll(user) | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
//store | ||
class SampleRoomStore(fetcher: Fetcher<User, String>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nothing crazy here besides a few interface changes that lead to a RoomInternalStore. TODO: create builders for instantiation |
||
persister: RoomPersister<User, List<String>, String>, | ||
stalePolicy: StalePolicy = StalePolicy.UNSPECIFIED) : | ||
RoomInternalStore<User, List<String>, String>(fetcher, persister, stalePolicy) | ||
|
||
val fetcher=Fetcher<User,String> { Single.just(User(name = "Mike", lastName = "naki")) } | ||
|
||
val store = SampleRoomStore( fetcher, persister) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
woohoo!