I'm developing a location aware app. This app will start tracking users when they are in their workday. These are the requirements:
The service should run on a regular basis (every 30 or 45 min).
It won't matter if the service does not trigger at the same basis everytime.
The service needs to upload data to our firestore db.
I doesn't need to be triggered on specific conditions (data is on, phone is charging, etc...)
I need this to run even if the user restarts his phone.
We may need to track the distance traveled by the user. (This is not a requirement per se, but it may be a feature someday)
I know there are a lot of ways to achieve this, but I have not decided which is the option that best fits my scenario. This is what I've thought so far:
Foreground service combined with BroadcastReciever in case the phone is rebooted
Background service using the new jetpack's Workmanager.
Which will the best solution? Do you think there is a better solution than those?
Thanks!
Was thinking create a GPS location tracker so when they are in work premise as well as outside it kinda shows.
Then consider adding the number 5 of the above. Like you said there could be mire awesome solutions than these so lets wait for options.
Related
I have a small test App that with an Android GPS API map fragment. I use FusedLocationProvider. TarketSDK=29. Using Java.
As long as the app is active it works beautifully. On locationUpdates, I add a new point to the track and everything looks great and stays accurate. The goal is to track my hike, total distance and track and show it on the map. Works great.
As soon I lock my phone or loses focus, then the updates stop and I no longer get location updates.
Solution seems to be:
Background Service (discouraged)
Foreground Service
PendingIntent
I have poured over the docs, StackOverflow, all examples/tutorials I can find, developer.android.com, etc. I have downloaded examples of the latter 2 from GitHub; they seem incredibly obtuse (probably just me).
What are the dis/advantages of ForegroundService vs PendingIntent?
How about a bare-bones example illustrating the min features of each to implement location updates while your phone is locked in your pocket or some other app is active? Just the template minimum.
I need to save the locationUpdates that occur while my app is not active or phone is locked; in order to fill in Track when activity is restored to the app.
Some simple end-to-end guidance from my working app to something that will maintain locationUpdates and save the data would be great.
Ok - I have answered my question in a roundabout way.
I had been Searching on "retrieving location updates when app is not active". This lead to the various solutions of background service, foreground service, pendingIntents, etc.
I eventually found that if you just start a Foreground Service with a Notification, even if your phone is locked or you switch active apps, your App continues to receive LocationUpdates; as the Foreground Service runs in the same thread and therefore activates your app code (if I understand the reasons why correctly).
So, I started searching on just how to start a Foreground Service. As anyone knows that has tried to figure this out lately, this has changed more than a couple times over recent versions. The online docs at developer.android.com are not up to date. You will spend a lot of time wondering why things do not work following these docs.
Eventually, with just searching on how to start a foreground service, I came across this simple and straightforward (non-youtube-video - don't you just hate those things) tutorial. https://androidwave.com/foreground-service-android-example/
I just added this code to my existing Mapping code that works when the app is active, and tested with locking the phone and putting it in my pocket and switching apps and doing the same. It appears to solve the problem.
Update: Added code to count number of location updates and average accuracy of each update holding the phone in hand, screen on and app active as the baseline. Phone locked, or App not active no difference in number of updates nor accuracy. Phone locked and in pocket, no difference in number of updates, but accuracy suffered by from an average of 10m to an average of 13m; to be expected I assume whilst in the pocket.
I'm developing a set of complications that I would like have regardless of the other installed apps and watch faces. Yes, at some point I am reinventing the wheel, but at the same time I am using this as a learning project. This will also ensure that I always have all the complications I use, available and that they all have the same format and style, instead of relying on 3rd party apps to provide them separately.
The set will have complications for Heart rate, gps coordinates, hours, minutes, seconds, dd/MM date, dd/MM/yy date, battery, etc.
When I started programing all this I found several problematic pieces (most likely because this is the first time I develop complications, or an app for android wear for that matter) and hence this question.
Note that some of this behavior might be specific to the Huawei Watch 2 LTE.
1) Upgrade interval push / pull.
I understand complications as data providers, whose only responsibility is to provide the data to whatever watch face is calling them. This means that we are not certain (and we rely on the watch face developer) to know about the complication and request updates accordingly. This turns some complications completely useless if not updated in time (for example display the Seconds). Could also leave to complications displaying old data (for example old GPS coordinates, old heart rate bpm).
So ok, I decided to implement ProviderUpdateRequester with the AlarmManager to push data to the watch face. The problem again, is with complications that should happen faster, like seconds, as Android will block pending intents if they are schedule too often. So in order to get around that, I decided to use Android handlers within the same service instance, which turn out to be not a good idea because of the next topic.
2) Complication lifecycle
By debugging, I found out that the instance of the ComplicationProviderService object that is executing onComplicationActivated, onComplicationUpdate, onComplicationDeactivated can be different. This means that this is not a sticky service (single instance) that will be always running, but every update creates a new instance of the service. This is problematic because of heavy initialization complications: for example GPS, or Heart Rate monitor that need to listen for new values and it might take a while to retrieve the first value. And also, for those complications that can't rely on AlarmManager, and/or need to keep some sort of state between updates executions.
3) Display aware service
To get around the previous point , let's say you have static variables on your complication service , which are initialized onComplicationActivated and disabled at onComplicationDeactivated. For example, this could be getting a reference for the LocationProvider and starting listening for location updates. This will ensure that each invocation to onComplicationUpdate will not have to perform the heavy/cold initialization and will have access to the most up-to-date data.
However, this also means that your logic will executed regardless if onComplicationUpdate is called or not.
When in ambient mode (or screen off) the watch face can decide not to update the complication by not calling onComplicationUpdate, but it's not aware of our static logic, nor the ComplicationProviderService has a callback invocation for when the screen goes into ambient mode or turns on/off. This is a problem, because in our example, if the screen is off, we are still going to be listening for GPS coordinates, and most likely draining the battery.
Sure, we can deal with this by using a combination of BroadcastReceiver (Intent.ACTION_SCREEN_ON/OFF) and DisplayManager.DisplayListener, but then again, not sure if i'm taking the correct path here, because this will mean that we are now creating services that need to be statically aware of the state of the display.
4) Detect screen on/off
The BroadcastReceiver for Intent.ACTION_SCREEN_ON/OFF works as expected when ambient mode is disabled, but it doesn't it's enabled. When ambient mode is enabled, Intent.ACTION_SCREEN_OFF is dispatched when going into ambient mode, but Intent.ACTION_SCREEN_ON is not dispatched when coming out of ambient mode. While a bit more complex, this can be accomplished by using DisplayManager.DisplayListener to get updates on the onDisplayChanged callback.
TL;RD
1) How do you ensure watch faces display your complications in a timely manner to always have correct and most up-to-date information?
2) How do you deal heavy/cold initialization of a ComplicationProviderService if everytime onComplicationUpdate is called the service instance is different?
3) Is making a long running service display-aware something crazy to do?
4) Technically the screen is still on when in ambient mode, so why is Intent.ACTION_SCREEN_OFF being broadcasted? Why isn't Intent.ACTION_SCREEN_ON/OFF symetrical when ambient mode is enabled?
5) Maybe complications shouldn't be use for exposing realtime information?
Thanks a lot
A couple of things to unpack:
Complications are not meant to be updated frequently (think minutes, not seconds) - this is to preserve battery.
ProviderUpdateRequester is designed more for (on average infrequent) irregular updates like messages coming through a chat app.
Time dependent complications - there are not an "update" as such but Wear provide ways for developers to count up / down from certain time and for displaying date related field (world clock, day of the month) without the provider sending the system updates all the time. For this last one, please refer to docs for ComplicationText.TimeDifferenceBuilder
and ComplicationText.TimeFormatBuilder.
For your use case, a more appropriate thing maybe to consider an always-on app. User uses it for a certain time period for a specific purpose so they explicitly agree to use to use more battery to track things like GPS or heart rate. For example, a lot of running apps on Wear do this.
I hope this helps.
I want to track user's real world activity on android ,which method is better ,GPS or activityRecognition?
and one of the situation is when user suddenly running, i want to detect user's activity change immediately how can i do?
According to your basic requirements I'll suggest you to use ActivityRecogniserAPI, but ActivityRecogniserAPI doesn't give you the results immediately specially on the places where Location Services are not responding quickly.
But if you use GPS then you can speedup the process little bit, but you have to do a-lot or work to achieve this by running some process, doing calculations, handling events etc. It will be little bit fast as compared to ActivityRecogniserAPI but you will be having issue in this as well when Location Services are not responding quickly.
If the slow process works for you then I'll suggest you to use ActivityRecogniserAPI.
Regarding the problematic stated below I have come to a point where I need to make a decision on whether to:
Start a Service once that has an AlarmManager inside which then starts the query every 10 minutes. This Service will only be stopped if the user sets an "Onn-Off" Switch to "Off".
Use an AlarmManager to start an IntentService every 10 Minutes. This Service will then only be started when needed and closed afterwards
Which of these ways is better when it comes to:
- Ability to exchange data received by the Service (Or Intenservice) with other activities/services
- Battery usage
- Overall "good coding habits" ?
Thanks!
Original Question:
I am a pretty new Android Developer and have come across a situation that I do not know how to solve. I have already spent several days searching for a solution but could not find one.
While trying to develop my first app idea I have started playing around with receiving and parsing data from the internet. What I have achieved so far is generating a query that receives JSON data via an API and parses this JSON. All of which is done inside an AsyncTask. The received data is then shown on the screen.
However, for the purpose of my app idea, I need this to be done in the background. What I have thought of is:
Starting a Service that pretty much has the same logic as my Asynctask. Managed by an AlarmManager, this service then requests, receives and parses the data in a specific time interval.
Now the tricky part begins:
The data that I receive (let's say every 10 minutes) shall be used to change an alarm clock. So, as a simple example, let's say the user can set his alarm clock to 08:00 in the morning. The application then checks the current temperature every 10 minutes and changes the alarm clock time to 07:45 if the temperature is below 0° celcius because the user has to wake up earlier to clear the ice off his car.
Also, when "waking up" the application, the current (or rather the latest received) tempereture shall be shown in the UI.
What would be the best way to achieve this? I am having some issues regarding passing/receiving data from AsyncTasks/Services to/from Activities.
My first approach would be to start a single service from the MainActivity, passing some data to the Service (like the initial time the alarm shall start and the current location of the user). The Service then has two seperate AlarmManagers. One of which is set to perform the actual alarm (waking up the user in the morning) and the other manages the time interval of getting the data from the internet.
My questions:
- Does my train of thought make any sense at all so far?
- What is the best way to pass and receive data to/from a service? My best guess would be to use intents to pass and a broadcastreceiver to receive data from the service. would this make sense in this specific situation?
I fear that it is not welcomed to post questions without putting in any effort of your own before. Although I did not add any actual source code, I hope you can see that I have dealt with these questions for quite a while now but could not really start coding before I know the structure of the application.
Thanks in advance
Use AlarmManager to start an IntentService as often as necessary (in your example, it should be sufficient to start checking the temperature about two hours before the user plans to get up and maybe again after one hour and finally half an hour before the normal wakeup time. More often only in case of extreme weather conditions.
It's not necessary to check the temperature exactly at 03:33 a.m. so use
setInexactRepeating(), this will be easier on the battery.
See also Scheduling Repeating Alarms
Write the results to SharedPreferences and have one IntentService check 15 minutes before normal wakeup time if the user should get up right then. Cancel the normal wakeup alarm in this case. Communicating via SharedPreferences (think of a mailbox) and local (!) Broadcasts is a good idea - cheap and secure :)
I've been looking everywhere for an example of code that is a Service that update a web server on the users location. this is made almost impossible because of the use of the word 'service' as it is used in the context of location service, for example 'googles location service'. please can anyone point me in the direction of an example where a SERVICE gets the location and does something with it. I can send it to a web service so I'm not asking for that but I just want to know if there is a way of every certain amount of time and distance a service will update the web server?
Look at Android docs about obtaining user location.
You will have to make several decisions:
How accurate do you need your updates to be?
How often do you need them?
This greatly affects device's power consumption. Personally I loathe the apps that prevent full sleep and have GPS constantly turned on - this drains the battery in a couple of hours.
I highly recommend you look at this blog post: A Deep Dive Into Location. There is a link to a great example app.