Skip to content

Live query doesn't unsubscribed. #91

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
VashchenkoAndrey opened this issue Sep 11, 2018 · 11 comments
Closed

Live query doesn't unsubscribed. #91

VashchenkoAndrey opened this issue Sep 11, 2018 · 11 comments
Assignees

Comments

@VashchenkoAndrey
Copy link

Backend:
Parse Server - 2.7.2
Database - PostgreSQL 9.5
Server OS - Ubuntu.

When I try to unsubscribe livequery, handleUnsubscribe doesn't worked, more than that handleSubscribe worked on closed activity. Help me please. My config:

class Application extends Application {

private ParseLiveQueryClient client;
private static Application instance;

onCreate(){
    // registerSubclasses
    // initialise Parse
    client = ParseLiveQueryClient.getClient();
    instance = this;
}

public static Application getInstance(){
    return instance;
}

public ParseLiveQueryClient getLiveQueryClient(){
    return client;
}

}

class BaseActivity extends AppCompatActivity {

private SubscriptionHandling<Message> messagesLQ;

public void onResume(){
    super.onResume();
    messageLQ = Application.getInstance().getLiveQueryClient()
        .subscribe(ParseQuery.getQuery("Message");
    messageLQ.handleEvent(Event.CREATE, (query, object) -> {
           // something should be there...
           // this code worked after closing activity
    });
}

 public void onPause(){
    super.onPause();
    Application.getInstance().getLiveQueryClient()
        .unsubscribe(ParseQuery.getQuery("Message"), messageLQ.handleUnsubscribe(query -> {
          messageLQ = null;
          // this code doesn't worked
    });
}

}

@mmimeault
Copy link
Contributor

mmimeault commented Sep 11, 2018

Hello,

Thanks for trying LiveQuery.

I'm not sure how the equals method is implemented on a ParseQuery.
But internally, the LiveQuery SDK use the equals method to find the subscribed query, if not found, it does nothing.

I suggest you to keep a reference to your ParseQuery instance and pass the same when unsubscribing.

query = ParseQuery.getQuery("Message");
Client.subscribe(query);
Client.unsubscribe(query);

Thanks

@mmimeault
Copy link
Contributor

mmimeault commented Sep 11, 2018

By the way, when unsubscribing, you can only pass the query. The SubscriptionHandling is optional. You have also the method with only the query.
Let's say you subscribe twice to the same query in 2 different place, you may want to only unsubscribe to 1 of it, this is where you would use the second parameter.

Every subscribe method will give you a SubscriptionHandling that is you hook to that subscription.

You should keep it like you do in the snipper if code.
But your

messageLQ.handleUnsubscribe(query -> {
          messageLQ = null;
          // this code doesn't worked
    }

Should be done when subscribing, not unsubscribing:

private SubscriptionHandling<Message> messagesLQ;
private ParseQuery<Message> query;

public void onResume(){
    super.onResume();
    query = ParseQuery.getQuery("Message");
    messageLQ = Application.getInstance().getLiveQueryClient().subscribe(query);
    messageLQ.handleEvent(Event.CREATE, (query, object) -> {
           // Handle create if wanted
    }).handleUnsubscribe(query -> {
          messageLQ = null;
          // unsubscribed! yay
    });
}

 public void onPause(){
    super.onPause();
    Application.getInstance().getLiveQueryClient().unsubscribe(query);
    // OR Application.getInstance().getLiveQueryClient().unsubscribe(query, messageLQ);
}

@VashchenkoAndrey
Copy link
Author

So, I tried a different ways to unsubscribe query. In fact, unsubscribe callback is not important for me. Important that when I call Client.unsubscribe(query, handling), subscription callback continued to work. It's not good. General problem is when I start new activity, new subscription (or thread or socket, not important) created, and subscription callback executed several times. What do you say to that?

@mmimeault
Copy link
Contributor

Could you please repost update code of your solution. That will help debugging.

Thanks.

@VashchenkoAndrey
Copy link
Author

May be I don't initialise something? I'm not trying to blame something. I'm really need help. I'm shocked.

@mmimeault
Copy link
Contributor

We are using parse live query at my job since we developed it and it is working great. Like you said, maybe it is a setup issue. Can you repost your up-to-date solution, it will help me debugging you.

Thanks

@VashchenkoAndrey
Copy link
Author

VashchenkoAndrey commented Sep 12, 2018

public class Avatar extends MultiDexApplication {

    private static Avatar instance;
    private ParseLiveQueryClient client;

    @Override
    public void onCreate() {
        super.onCreate();
        Fabric.with(this, new Crashlytics());
        instance = this;
        // register subclasses
        Parse.initialize(new Parse.Configuration.Builder(this)
                .applicationId(ParseConfigs.APP_ID)
                .server(ParseConfigs.SERVER_URL)
                .clientKey(ParseConfigs.CLIENT_KEY)
                .build());

        client = ParseLiveQueryClient.Factory.getClient();
        ParseFacebookUtils.initialize(this);
    }

    public static Avatar getInstance(){
        return instance;
    }

    public ParseLiveQueryClient getLiveQueryClient(){
        return client;
    }
}

public abstract class BaseActivity extends AppCompatActivity {

     public ParseLiveQueryClient getLiveQueryClient(){
        return Avatar.getInstance().getLiveQueryClient();
    }

    @Override
    protected void onPause() {
        super.onPause();
        destroyLiveQuery();
    }

    @Override
    protected void onResume() {
        super.onResume();
        update();
        setUpLiveQuery();
    }

    public void update(){
        Avatar.getInstance().getLiveQueryClient().connectIfNeeded();
    }

    public void setUpLiveQuery(){
        // overrided
    }

    public void destroyLiveQuery(){
        // overrided
    }
}

public class MainActivity extends BaseActivity {

    private SubscriptionHandling<DialogInfo> messagesLQ;
    private SubscriptionHandling<PNotificationsInfo> notifiesLQ;

    @Override
    public void setUpLiveQuery() {
        messagesLQ = getLiveQueryClient().subscribe(ParseHelper.getTotalUnreadMessagesQuery());
        messagesLQ.handleEvents((query, event, object) -> {
            switch(event){
                case CREATE:
                case ENTER:
                case UPDATE:
                    // something should be there
                    // this code worked after closing activity
                    break;

                default:
                    break;
            }
        });

        notifiesLQ = getLiveQueryClient().subscribe(ParseHelper.getTotalUnwatchNotificationsQuery());
        notifiesLQ.handleEvents((query, event, object) -> {
            switch(event){
                case CREATE:
                case ENTER:
                case UPDATE:
                    // something should be there
                    // this code worked after closing activity
                    break;

                default:
                    break;
            }
        });
    }

    @Override
    public void destroyLiveQuery() {
         getLiveQueryClient().unsubscribe(ParseHelper.getTotalUnreadMessagesQuery(), messagesLQ);
         getLiveQueryClient().unsubscribe(ParseHelper.getTotalUnwatchNotificationsQuery(), notifiesLQ);
    }

@VashchenkoAndrey
Copy link
Author

thank you

@VashchenkoAndrey
Copy link
Author

I understood what the error was. In unsubscribe method I passed a new instance of the same query. In implementing the live query client method "unsubscribe" developer use non-override "equals" (==) which only check links, not body. In result, I had to store all parse query as a singleton. I think, it's not good way, "equals" for complex objects should be override.

@VashchenkoAndrey
Copy link
Author

VashchenkoAndrey commented Sep 12, 2018

class ParseLiveQueryClientImpl implements ParseLiveQueryClient {
    -----------------------------------
    @Override
    public <T extends ParseObject> void unsubscribe(final ParseQuery<T> query) {
        if (query != null) {
            for (Subscription<? extends ParseObject> subscription : subscriptions.values()) {
                // that "equals" should be override
                if (query.equals(subscription.getQuery())) {
                    sendUnsubscription(subscription);
                }
            }
        }
    }

    @Override
    public <T extends ParseObject> void unsubscribe(final ParseQuery<T> query, final SubscriptionHandling<T> subscriptionHandling) {
        if (query != null && subscriptionHandling != null) {
            for (Subscription<? extends ParseObject> subscription : subscriptions.values()) {
                // that "equals" should be override
                if (query.equals(subscription.getQuery()) && subscriptionHandling.equals(subscription)) {
                    sendUnsubscription(subscription);
                }
            }
        }
    }
    --------------------------------
}

@mmimeault
Copy link
Contributor

@Deamond12333 Yes I'm happy that found that :). But this is pretty much what I explained you in that previous answer #91 (comment)

I'm not sure about all the reason of not implementing a proper equals on a query, but for now you should keep a reference to it, not necessary as a singleton, depending how your project is built.

In our application we have one classe to manage the query and handle all the answer.
We use the same query to first do a call to fetch actuals results, and then re-used it when subscribing for changes with live query. Then on the shutdown of that class, we first unsubscribe from the live query client then we cancel the query (query.cancel()).

That managing class can be a singleton OR can only live for the duration of your activity lifecycle. Up to you...

But I think it is good pattern to keep a reference to the query..
1- To reuse it
2- To proper cancel it when done

Thanks
Michael

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

No branches or pull requests

2 participants