Android: Query is slow | /system_process W/ActivityManager﹕ Launch timeout has expired, giving up wake lock!

Hi,

I am trying to develop an Android App with Couchbase. I have a conversations that need to be shown in a Activity. But the time taken to display the content is bit more and I am seeing the below in my logs:

499-514/system_process W/ActivityManager﹕ Launch timeout has expired, giving up wake lock!

I did try to find the solution and while looking for the solution I found that my UI thread was handling too many operations, So I put all the querying the database onto AsyncTask to make the UI thread light weighted.

But still I am getting the latency in displaying the content and same thing in the logs.

This issue didnot arise when I am using a REST API which internally calls a MySQL database.

Below are the details of my query:

My view :
View productView = DBHelper.database.getView(“chatDetailsView”);
productView.setMap(new Mapper() {
@Override
public void map(Map<String, Object> document, Emitter emitter) {
Object type = document.get(“type”);
if (type != null && type.equals(“chat_message”)) {
emitter.emit(document.get("_id"), document);
}
}
}, “0005”);

Query :

Query query = DBHelper.database.getView(“chatDetailsView”).createQuery();
query.setStartKey(“chat_message_user_” + LoginUserHelper.getUserId()+ “user” + contactNumber + “\u02ad” );

    query.setEndKey("chat_message_user_" + LoginUserHelper.getUserId() + "_user_" + contactNumber); 

query.setDescending(true);

QueryEnumerator result = query.run();

// Then I iterate through the data and use it to display.

Please let me know why is this issue happening? Please let me know in case of further details are required.

Thanking you,

Hi @rameshnittali, did you debug your code to see which parts are the slowest? For example how much time does the query take to execute, compared with the iteration of the results, etc.

Check this implementation, it’s similar to your solution and we have no performance issues with it

Regards,
Vlad

Hi vladoatanasov,

Now I changed my approach to use liveQuery as you suggested above. But I notice a lag of almost a minute between calling of method setupLiveQuery() to method changed().I will illustrate the approach I am using, please correct me if I am wrong.

In the method onCreate of my activity I call setUpLiveQuery. Below is the code:

 private void setUpLiveQuery() {
final ProgressDialog progressDialog = showLoadingSpinner();


Query query = DBHelper.database.getView("chatDetailsView").createQuery();
query.setStartKey("chat_message_user_" + LoginUserHelper.userdata() + "_user_" + contactNumber + "\u02ad");
query.setEndKey("chat_message_user_" + LoginUserHelper.userdata() + "_user_" + contactNumber);
query.setDescending(true);

Log.v("start of method setupLiveQuery","");

LiveQuery liveQuery = query.toLiveQuery();
this.liveQuery = liveQuery;


liveQuery.addChangeListener(new LiveQuery.ChangeListener() {


    @Override
    public void changed(final LiveQuery.ChangeEvent event) {

        
         Log.v("Inside method changed","");

        runOnUiThread(new Runnable() {
            public void run() {

               // Iterating through the data fetched goes here

            }
        });
    }
});
this.liveQuery.start();

}

Now notice the log inside setUpLiveQuery() and changed() When I run, the changed() method is called almost a minute later. Please find the logs below:

12-08 17:28:48.239 1977-1977/com.chromosis.wishhapp.wishhapp V/start of method setupLiveQuery﹕
12-08 17:29:48.871 1977-2005/com.chromosis.wishhapp.wishhapp V/Inside method changed﹕

The execution after that seem faster but the callback to changed() method is taking long time.

Please suggest if my approach is appropriate.

Hi @rameshnittali, your approach is also right. I’m just using a live query in my example to implement a more event driven approach, but this is not what’s causing the problem on your side.

I am not sure why you are getting this performance, one second sounds like a lot. How many documents do you have in your bucket and how many are the emitted documents from the view?

Regards,
Vlad

Hi Vlad,

We are still in development stage and the total documents may be around 1000. This particular use case deals with only documents of type “chat_message”, and the count of documents of this type may not be exceeding 200 as of now but may increase a lot in production.

below is the code of my views:

View chatView = DBHelper.database.getView("chatDetailsView");
chatView .setMap(new Mapper() {
    @Override
    public void map(Map<String, Object> document, Emitter emitter) {
        Object type = document.get("type");
        if (type != null && type.equals("chat_message")) {
            emitter.emit(document.get("_id"), document);
        }
    }
}, "0005");

my usecase is as below :

We are trying to make a chat application, when one user creates sends a message we create 2 documents

  1. with id “chat_message_user_<sender_userid>user<recipient_id>”
  2. with id “chat_message_user_<recipient_id>user<sender_userid>”

each document will be used for the respective user’s to view in their conversation.

So I query like below :

Query query = DBHelper.database.getView("chatDetailsView").createQuery();
query.setStartKey("chat_message_user_" + LoginUserHelper.userdata() + "_user_" + contactNumber + "\u02ad");
query.setEndKey("chat_message_user_" + LoginUserHelper.userdata() + "_user_" + contactNumber);
query.setDescending(true);

For example logged in user is xyz and another party in the conversation is abc

then the documents we want to query are with ids chat_message_user_xyz_user_abc.

Please let me know if the approach is appropriate.

The point here is that the call back method “changed()” is being called almost a 60 seconds delay. The query seem to be executing pretty faster. Kindly help.

Hi @rameshnittali, I am not sure why you have this delay. One thing I forgot to ask is, if you experience this behavior only on the first run of the app, maybe it just takes time to build the indexes the first time.

About the approach, are you using the sync gateway? If so, maybe it will be better to utilize the channels, users and roles, to route the documents to the users you want. You can read about it here http://developer.couchbase.com/documentation/mobile/current/develop/guides/sync-gateway/channels/index.html

The basic concept is tagging the messages, so you create one message with channels Ramesh and Vlad, this way both of us can read it, nobody else would.

Regards,
Vlad

In your view are you emitting the whole JSON document as the VALUE in your view?

Hello,

Yes, I am emitting the entire document. Is it not the appropriate way? Kindly suggest.

The view is just a user defined index. So what you want is to query the view for what satisfy your question. It will return back a result of the document key(s) and you can do a fetch for the document keys. This way do you not store the document twice.

The results are returned as a QueryEnumerator object, which mainly serves as an enumerable collection of QueryRow objects. We then iterate over the results getting each QueryRow. For each QueryRow in the results, we find the ‘docId’ and use an EventRepository to fetch the actual complete Event object from the Sync Gateway.

Source: Couchbase Capella for Mobile Developers