By referring to Proper way to tackle and resolve "Excessive network usage (background)"
After few months of debugging, we are now able to run all network related code in Foreground service.
However, we are still getting "Excessive network usage (background)" warning in Android Vital.
When foreground service code is executed, a notification UI will always shown in status bar area.
When we "quit" our app, we launch the foreground service, using WorkManager
. The WorkManager
will return immediately, after foreground service is launched.
public class SyncWorker extends Worker {
@NonNull
@Override
public Result doWork() {
final Intent intent = new Intent(WeNoteApplication.instance(), SyncForegroundIntentService.class);
ContextCompat.startForegroundService(
WeNoteApplication.instance(),
intent
);
return Result.success();
}
}
public class SyncForegroundIntentService extends IntentService {
private static final String TAG = "com.yocto.wenote.sync.SyncIntentService";
public SyncForegroundIntentService() {
super(TAG);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
final Context context = WeNoteApplication.instance();
NotificationCompat.Builder builder = new NotificationCompat.Builder(...
startForeground(SYNC_FOREGROUND_INTENT_SERVICE_ID, builder.build());
// Perform networking operation within foreground service.
stopForeground(true);
We don't think we are sending a lot of data. As you can see our latest release, we fall in the lowest range (0 - 5 MB per hour)
Any idea why we're still getting "Excessive network usage (background)"? Apparently, we no longer perform any networking call in background.
We utilize https://developer.android.com/reference/android/app/Service.html#startForeground(int,%20android.app.Notification) and https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)
To start a foreground service, call startForeground() . To stop it, call stopForeground() .
Foreground services According to the official android documentation, a foreground service performs operations that are noticeable to the user. It shows a status bar notification, so that users are actively aware that your app is performing a task in the foreground and is consuming system resources.
Inside the service, usually in onStartCommand() , you can request that your service run in the foreground. To do so, call startForeground() . This method takes two parameters: a positive integer that uniquely identifies the notification in the status bar and the Notification object itself.
A Background Service is a service that runs only when the app is running so it'll get terminated when the app is terminated. A Foreground Service is a service that stays alive even when the app is terminated. And a Bound Service is a service that runs only if the component it is bound to is still active.
You are using a Worker
to invoke the ForegroundService
. From the Worker
's documentation:
Worker classes are instantiated at runtime by WorkManager and the doWork() method is called on a pre-specified background thread (see Configuration.getExecutor()). This method is for synchronous processing of your work, meaning that once you return from that method, the Worker is considered to be finished and will be destroyed. (...) In case the work is preempted for any reason, the same instance of Worker is not reused. This means that doWork() is called exactly once per Worker instance. A new Worker is created if a unit of work needs to be rerun.
A ForegroundService
is a Service
that you put in the foreground state, that means, the system will not kill the process if it needs CPU or if your app is closed. This and only that.
I wasn't able to find the documentation of Android Vital proving this, so this is only my suspicion, but I'm quite positive this is the case: this means that regardless of the fact that you use ForegroundService
or not, Android Vital still counts this as background work.
A proper way to move your app’s mobile-network usage to the foreground is to call DownloadManager
with proper visibility setting set (as stated in the link you have provided). Please let me know if that helps - if not we'll try something different. Btw, were you able to narrow down the statistics to a specific API version? (there were some background threading changes in 9.0 and 8.0 so this can also be a clue)
If you're doing this:
When we "quit" our app, we launch the foreground service, using WorkManager. The WorkManager will return immediately, after foreground service is launched.
then you're technically scheduling a worker probably with network constraints every time the user shuts the app.
From the documentation for "Excessive background network usage" link
When an app connects to the mobile network in the background, the app wakes up the CPU and turns on the radio. Doing so repeatedly can run down a device's battery
Thus, even though you're not sending the threshold data of 50MB/ 0.10% of Battery session you're getting this warning cause your app is technically waking up the CPU a lot in the background (for network pings).
Though i'm not sure if this is the problem or not, what you can do is, since even the worker documentation guide says:
WorkManager is intended for tasks that are deferrable—that is, not required to run immediately—and required to run reliably even if the app exits or the device restarts
you can try these:
Scheduling a foreground service as soon as the user shuts the app, instead of scheduling a worker, checking inside the onHandleIntent
whether the user is online or not (having a connection and for devices above 7, a flowing internet connection as well).
You can try scheduling a worker to run periodically, lets say every few hours based on your business-side requirements, this could be problem if that's not how you wish to back-up the data, but it serves the real purpose of the worker being a deferred task and not something to be executed immediately.
Not sure about this, never tried, but theoretically looks valid, you can use a Unique Work with a mode called REPLACE
to replace the worker and have an initial delay of lets say 30mins, this is a hack, but this will delay running of your worker for 30mins, and in the meanwhile if the user opens and shuts the app again, it will replace the old worker with a new one. This solution has its own drawbacks as well, like sometimes the task wont be scheduled if the user is using the app constantly. But will reduce the total number of times the worker had ran.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With