square / sqlbrite

A lightweight wrapper around SQLiteOpenHelper which introduces reactive stream semantics to SQL operations.
https://square.github.io/sqlbrite/3.x/sqlbrite/
Apache License 2.0
4.57k stars 419 forks source link

[Q] How to implement memory cache if i using BriteDatabase.createQuery()? #240

Closed Guang1234567 closed 6 years ago

Guang1234567 commented 6 years ago

Hello dev:

How to implement memory cache if using BriteDatabase.createQuery? Could you give me some suggestion?

My code is below, but it does not working (I using cancat operator)


public class MainRepository implements MainDataSource {

    private final ListsItemDao mListsItemDao;

    @VisibleForTesting
    @Nullable
    Map<Long, ListsItem> mCachedListsItems;

    @Inject
    public MainRepository(ListsItemDao listsItemDao) {
        mListsItemDao = listsItemDao;
        mCachedListsItems = new HashMap<>();
    }

    @Override
    public Observable<List<ListsItem>> createQueryListsItems(final long max) {
        Observable<List<ListsItem>> disk =  mListsItemDao.createQueryListsItems(max) // 省内存
                .doOnNext(new Consumer<List<ListsItem>>() {
                    @Override
                    public void accept(List<ListsItem> listsItems) throws Exception {
                        mCachedListsItems.clear();
                        Iterator<ListsItem> it = listsItems.iterator();
                        while (it.hasNext()) {
                            ListsItem listsItem = it.next();
                            mCachedListsItems.put(listsItem.id(), listsItem);
                        }
                    }
                });

        Observable<List<ListsItem>> memory = Observable.create(new ObservableOnSubscribe<List<ListsItem>>() {
            @Override
            public void subscribe(ObservableEmitter<List<ListsItem>> e) throws Exception {
                    e.onNext(new ArrayList<ListsItem>(mCachedListsItems.values()));
            }
        });

        return Observable.concat(memory, disk).firstOrError().toObservable();
    }
}

In addition, MainRepository.createQueryListsItems(100L) must receive change event after Database was modified by BriteDatabase.insert(...)

ShaishavGandhi commented 6 years ago

firstOrError() returns a Single which means it will only emit one item. Converting it to an Observable with toObservable() will not convert it into a "hot" observable. If you want changes on database to propagate to your View layer and want a memory cache, you could look for something like PublishSubject or PublishRelay which is both an Observer and Observable. i.e it can listen to changes in database, store them in cache and relay them on to the View layer.

This doesn't seem to be a SQLBrite related question

JakeWharton commented 6 years ago

I would recommend using https://github.com/JakeWharton/RxReplayingShare which will share the latest value to any new subscriber synchronously and then attach to the existing query for future updates.

Guang1234567 commented 6 years ago

@shaishavgandhi05
@JakeWharton

Thank you for your valuable advice.

Guang1234567 commented 6 years ago

@JakeWharton

Althought using RxReplayingShare, but

Query.run() everytime after rotate the display because startWith operator in

https://github.com/square/sqlbrite/blob/e235fde6e2aa9c8813605dc73cead37c7dd9f3f2/sqlbrite/src/main/java/com/squareup/sqlbrite3/BriteDatabase.java#L386

Do you have any idea to avoid this redundant Query.run() after rotate the display?

JakeWharton commented 6 years ago

No. It shouldn't matter because at worst it re-queries the cached information and at best you get updated results.

On Tue, Mar 13, 2018 at 4:36 AM GuangGuang notifications@github.com wrote:

@JakeWharton https://github.com/jakewharton

Althought using RxReplayingShare https://github.com/JakeWharton/RxReplayingShare, but

Query.run() everytime after rotate the display because startWith operator in

https://github.com/square/sqlbrite/blob/e235fde6e2aa9c8813605dc73cead37c7dd9f3f2/sqlbrite/src/main/java/com/squareup/sqlbrite3/BriteDatabase.java#L386

Do you have any idea to avoid this redundant Query.run() after rotate the display?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/sqlbrite/issues/240#issuecomment-372586581, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEERlE7rC6a_eoz52gexBh9bZpsEQjks5td4TcgaJpZM4Sl-mK .