Skip to content
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

Querying the 'activity' data type with 'includeCalsAndDist' flag set to true is very slow (Android) #293

Closed
TeoMastro opened this issue Aug 18, 2023 · 8 comments

Comments

@TeoMastro
Copy link

TeoMastro commented Aug 18, 2023

Hello,
When I query the 'activity' data type with the 'includeCalsAndDist' flag set to true, I am getting a delay of about 15 to 18 seconds. Note that I use the .query() function and the data that I am querying is for the last 30 days. So the way I construct my query is:

   let query: any = {
      startDate: new Date(new Date().getTime() - 30 * 24 * 60 * 60 * 1000), // last 30 days
      endDate: new Date(), // now
      includeCalsAndDist: true,
      dataType: 'activity'
    };

and the way I actually query for the 'activity' data type is:

import { Health } from '@awesome-cordova-plugins/health/ngx';
constructor(private health: Health) {}
await this.health.query(query); // I use this line inside a function

This is pretty standard according to the documentation of the plugin, and has worked for me for other data types (e.g. blood pressure, oxygen saturation).

In order to see what was wrong and I was witnessing this long delay, after I made sure my code was ok, I starting digging at the plugin source code (the HealthPlugin.java file in particular). I found out that inside the query function of the plugin, there is a specific line of code that caused the problem:

// Active wait. This is not very efficient, but otherwise the code would become hard to structure
DataReadResponse dataReadActivityResult = Tasks.await(activityTask);

I am pretty sure that this is causing the problem with my delay, since this line runs when includeCalsAndDist is true and also runs multiple times since this code is wrapped in a double for loop (note that when includeCalsAndDist is set to false there is no perfomance issue). I also used System.currentTimeMillis() in order to measure the time that the Tasks.await(activityTask) is taking and I found out that this 'Active wait' (as mentioned in the comment on the code block above) is running multiple times and is causing an overhead in time.

But there is more to the story. In an older (ionic-4) company project that uses cordova plugins only and java 11 (target sdk 32), this particular query works without any problems (I use the same version of the plugin) in the same way that I am trying to use it now in a newer company project that we are building at the moment.
The project in which I have the problem utilizes:

  • Capacitor 5
  • Ionic 6
  • Java 17 (Target SKD 33)

Also, I would like to note that I did not witness the same behavior when I queried for activities on IOS.
I suspect that there is something that might have changed with Android or Java (the Tasks object maybe) that is causing the same native code to run insufficiently.

Since I am not familiar with native code and plugin development in Java, I will probably not be able to provide any solution for this problem. Any help or suggestion would be appreciated.

@dariosalvi78
Copy link
Owner

dariosalvi78 commented Aug 18, 2023

The Tasks.await() only affects how the plugin interacts with the main thread, it is not in itself the cause of your issue. The cause of the issue is that, when adding calories and distance, the plugin makes several queries, because this is not a standard feature of Google Fit (as opposed to HealthKit). Basically, for each single activity in your 30 days time, the plugin needs to issue an additional query to determine the distance walked and the calories, which can take time.

There is not much to do about it, but I can suggest a) to not query calories and distance (do you really need it?) or b) try with shorter periods of time.

Just to be sure that the problem is the one I have suggested, try issuing a query for a shorter period, like 1 day, and check if it's quicker.

Another thing: you mention that this does not ocurr in an older version of the app: does that app use the same time window? What version of the plugin did that app use?

@TeoMastro
Copy link
Author

I understand that "Basically, for each single activity in your 30 days time, the plugin needs to issue an additional query to determine the distance walked and the calories, which can take time.", and I already saw an older issue where you suggested the use of aggregated queries instead of normal queries.
About a) I need calories and distance for each individual exercise, that is the case for me.
About b) I already tried with sorter periods of time, it seems to work more efficiently for 2-3 days but when I try to query 10 days or a week, I still get a long delay.
The older app also uses the same time window (30days) and it uses the exact same version of the plugin. I already checked that the sha512 strings are the same for the older and the newer app inside the package-lock.json ( for the @awesome-cordova-plugins/health and the cordova-plugin-health).
Do you have any other suggestions? Thanks for your time in advance.

@dariosalvi78
Copy link
Owner

Consider that the queries are run in a separate thread, so the wait() in itself shouldn't be a problem, but if we could avoid the wait() and run the queries in parallel we could get even more speed I guess.

The fact that the same plugin is fast on an older version of Java and Capacitor is strange: how would they impact the plugin? Tasks are explained here, I don't see anything about new versions of Java, but maybe the new Capacitor may affect the execution? The plugin attaches the Fitness API client to the Cordova activity (see this.cordova.getContext()), but in Capacitor this may work somewhat differently. I have no idea TBH.

Another question: you mention that the app spends a lot of time on Tasks.await(activityTask);. These correspond to the query where we get calories and distance. I would expect these calls to be fast but high in number (which would make the sum of the time long). Is that the case? Can you estimate how many calls are made for a 30 days window of time? Do the queries take a long time?

@TeoMastro
Copy link
Author

The thought of one of my colleagues was exactly this one: "but if we could avoid the wait() and run the queries in parallel we could get even more speed I guess."

I really have no deep insight on how Java or Capacitor or this.cordova.getContext() could affect the execution of the plugin.

About your question: I was recording my movements for the last 2 weeks, so in the timeframe of a month I have about 350 different google activities returned as a result when 'activity' is queried. Note that I use my personal phone and Google fit account for testing purposes. So the calls are indeed high in number, but each one awaits individually for about 10 to 60 ms. This sum is what makes the wait time so high. These small time values definitely stack up to a bigger timeframe of waiting.

Maybe there might be someone else that can provide us with insights about how Java, Capacitor or this.cordova.getContext() affect the runtime of the plugin. Or there might be someone else with the same problem.

@dariosalvi78
Copy link
Owner

There may be a way to speed up the queries by running them in parallel (maybe), but it's not trivial, especially in this case where we need to aggregate the results from the queries.

The queries take a reasonable amount of time, but they are many, so I see where the issue is. I would ask around if someone else has experienced something similar. It may also due to something new on the Google Fitness APIs.

I am going to close the issue because it's not really related to the plugin (except some possible optimizations).

@TeoMastro
Copy link
Author

Well, in my humble opinion it not that unusual that someone would query activities with 'includeCalsAndDist' set to true for a time period of 1 month. I get why you say that this issue is not related to the plugin, but when for my data (which are simple data you can get by walking and light exercising for 2 weeks) I have to wait for around 15 to 18 seconds, this renders the querying of activities with 'includeCalsAndDist' unusable for a median user.

@dariosalvi78
Copy link
Owner

we can create a separate issue to parallelize the queries for calories and distance. I doubt I will have time to work on it though, but maybe someone picks it up?

@dariosalvi78
Copy link
Owner

see #294

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