Skip to content
This repository has been archived by the owner on Aug 17, 2020. It is now read-only.

mDataManager.getContentQuery(catId).subscribe called multiples times #171

Closed
joginder89 opened this issue Feb 4, 2017 · 7 comments
Closed

Comments

@joginder89
Copy link

I have created a getContentQuery(int catId) method which return Observable<SqlBrite.Query> . Problem is that when I called mDataManager.getContentQuery(catId).subscribe() then call(SqlBrite.Query query) of Action1 inside .subscribe() executes multiple times. I used .doOnNext(new Action1<SqlBrite.Query>() this also called multiples times.

@JakeWharton
Copy link
Member

Can you provide an executable test case that demonstrates the problem?

@joginder89
Copy link
Author

joginder89 commented Feb 6, 2017

Hi, I have a RecyclerView, When user reach to end of list, I call an API and fetch data from Server and add that data in Local database as

`BriteDatabase.Transaction transaction = db.newTransaction();
try {

        for (ContentModel contentModel : contentList) {

            try {

                db.insert(Db.ContentTable.TABLE_CONTENT, Db.ContentTable.toContentValues(contentModel));

            } catch (Exception e) {

                Logger.e("DatabaseHelper", e.getMessage());

            }

        }

        transaction.markSuccessful();

    } finally {

        transaction.end();

    }`

and after inset I fetch data from Local database as

`mDataManager.getContentQuery(catId)

            .subscribeOn(mDataManager.getScheduler())

            .observeOn(AndroidSchedulers.mainThread())

            .subscribe(new Action1<SqlBrite.Query>() {

                @Override public void call(SqlBrite.Query query) {

                    Cursor cursor = query.run();

                    List<ContentModel> result = new ArrayList<>();

                    while (cursor.moveToNext()) {

                        ContentModel content = Db.ContentTable.parseCursor(cursor);

                        result.add(content);

                    }

                    cursor.close();

                    updateAdapter(result);

                }

            });`

`public Observable<SqlBrite.Query> getContentQuery(int catId) {

        return db.createQuery(Db.ContentTable.TABLE_CONTENT, "SELECT * FROM " + Db.ContentTable.TABLE_CONTENT + " WHERE category_id=" + catId + " ORDER BY id DESC");

}`

Now problem is that updateAdapter(result); is called multiple times, and its count increase by one with every server API call, for eg when I fetch data from server from id 30-40 its called 3 times, when 40-50 it called 4 times, from 50-60 it called 5 times and so on. When its called more then 20 times my RecyclerView get hang and screen get freeze. This may not be an issue with library but It create problem for me.

@joginder89
Copy link
Author

.subscribe(new Action1<SqlBrite.Query>() { also run the previous Query which I have run during this session. I do not understand when I fetch some data why It run previous query also. I have a single object of DataManager. How can I do that when I fetch some data from local database then It do not run previously run query again ?

Like If I print Logger.d(TAG, "query-" + query); inside .subscribe(new Action1<SqlBrite.Query>() { @Override public void call(SqlBrite.Query query) { then it print

query-SELECT * FROM content WHERE category_id=288 ORDER BY id DESC
query-SELECT * FROM content WHERE category_id=314 ORDER BY id DESC
query-SELECT * FROM content WHERE category_id=311 ORDER BY id DESC

where I run only last one query and previous queries was run in past. Whenever I run any query It run all past query also.

@JakeWharton
Copy link
Member

Without a test case or a sample it's impossible to know what's going on.

@joginder89
Copy link
Author

Hi I have added a sample project https://github.com/joginder89/SqlBriteSample .
When I click Get More it fetch data from server save in local database and show on view.

@rostyslav-y
Copy link

rostyslav-y commented Jun 12, 2017

@joginder89 It looks like you have no unsubscribe logic(showContent method). So every time when you call showContent(int catId), it adds one more Observer<SqlBrite.Query> to already existing. You need to add some subscription management logic to release those subscription that are no longer needed, something like this:

    private Subscription mContentSubscription;

    public void showContent(int catId) {
        Log.e(TAG, "showContent=>Start");
        if (mContentSubscription != null && !mContentSubscription.isUnsubscribed()) {
            mContentSubscription.unsubscribe();
        }
        mContentSubscription = MyApplication.get().getDataManager().getContentQuery(catId)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<SqlBrite.Query>() {
                    @Override
                    public void call(SqlBrite.Query query) {
                        Log.e(TAG, "showContent=>query-" + query);
                        Cursor cursor = query.run();
                        Log.e(TAG, "showContent=>cursor.getCount()-" + cursor.getCount());
                        List<ContentModel> result = new ArrayList<>();
                        while (cursor.moveToNext()) {
                            ContentModel content = Db.ContentTable.parseCursor(cursor);
                            result.add(content);
                        }
                        cursor.close();
                        updateAdapter(result);
                    }
                });
    }

@JakeWharton
Copy link
Member

Basically what @rostyslav-y said, you need to track subscriptions to prevent old queries from triggering over and over. This is a general RxJava idiom, and not specific to this library.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants