0

Project statement:

i have a simple counter app which has 6 things i am counting. on my wearable, i have a radiobutton group which selects which of those things i want to count. it then displays the current count for the item on the watch and then i can either add or subtract 1 from it from the watch. The watch is only an interface and interaction device. it does no processing. All processing of information and storing of information is done on the mobile. so the watch merely sends messages and displays information.

How it works:

the wear sends messages to the mobile via Wearable.MessageApi.sendMessage() and the phone responds with Wearable.DataApi.putDataItem(). The watch is sending multiple forms of informaiton like add/subtract/countRequest in addition to which item it is references. the mobile only responds with the item count requested and the watch only need change the display if it is a different value than what is showing.

This is a general messenger understanding question. I have

public class MyListenerService extends WearableListenerService{
    @Override
    public void onMessageReceived(MessageEvent me){
        showToast();
    }
}

The listener works. Now i want to do something useful with the listener because it is actually sending data i need. But i am having trouble communicating between Service and Activity because of my limited experience. I have read up on messaging and broadcast receivers. and am looking for ideas on how to implement to get my result or a better understanding.

From what i am gathering from trying to code, a service cannot directly interact with my interface, so i need to communicate with my activity in some way. 2 ways i have read is messaging(handlers) and broadcastreceivers.

each of these methods will do the function, however have their drawbacks which is where i am looking for better understanding or help.

for the Handler: even though i can create a static handler class and run code within the handler class, because it is static i cannot call non static objects which means if i try and do this it fails.

Service:

public class MyListenerService extends WearableListenerService{
    @Override
    public void onMessageReceived(MessageEvent me){
        Activity.mHandler.sendEmptyMessage(MyConstants.COMMAND);
    }
}

Activity:

public static Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        doThis(msg.what);
    }
}; 

private void doThis(int command){
    processCommand();
    updateUserInterface();  
}

Is there a way i can implement the above Handler, because when i process message if i just simply do a toast, it works, so i can receive the message. I just cant call a non-static object from a static. so i am assuming i cannot update an interface object either if i just threw the code of doThis() inside the Handler since i am just using it as a go between. When i was using LiveListeners and the onMessageReceived() was within my Activity, rather than a separate service, i just called doThis() directly and it worked great. for the BroadcastReceiver: There is a lot of code to show so instead i will just explain my issue for it and you may be able to answer from that. apparently you have to register/unregister on onResume()/onPause(). That would prevent me from being able to process information when the phone goes to sleep. the whole point of running a service is so i can do stuff when the phone is asleep or the activity is not in the foreground.

Before i was doing "LiveListeners" and it worked fine, so long as activity was in the foreground and phone was not sleeping. only way to have it work while sleeping is to engage a service to work in the background.

So my question is, what is best way to handle this situation so that i can process the information that the wearable is sending to the mobile while the mobile is asleep. or is there another method to send data i did not find?

John Bravado
  • 137
  • 4
  • 10

2 Answers2

1

If you extend WearableListenerService, you are creating a special Service which runs as part of your app's process. You can use this to communicate with another Service in your app which does all the processing, or use broadcasts (as you noted.) In either case, the Service is running in the context of your process and on the main thread - so if you need to do any heavy processing you'll need to offload it to a background thread.

Since your WearableListenerService is declared in the manifest and its lifecycle managed by Android Wear (by default), it's going to be simplest to either create a secondary Service or use a BroadcastReceiver to do your processing. Just note that "processing" must be lightweight if in a BR. If you use a BR, look into using LocalBroadcastManager as it is more efficient than sending the broadcast via the usual Context.sendBroadcast(). It's roughly the equivalent of sending a message to your app, it just happens to be in Intent form.

Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • How would a second process be beneficial. Wouldn't i be in the same boat. Unable to communicate with the main UI thread. And i am assuming i can make service run in the background on separate thread easy enough by just instantiating a runnable inside the onCreate() of the service? or would i do it in th eactivity – John Bravado Dec 28 '16 at 14:36
  • Sorry forgot to hodl shift when hitting enter – John Bravado Dec 28 '16 at 14:37
  • arghhh finishing - in the activity start the thread when calling startService()? and regarding the BroadcastReceiver, does it run in the background when phone is asleep? the service runs while phone is asleep, but the broadcastreceiever apparently does not. Or am i mistaken on that? – John Bravado Dec 28 '16 at 14:39
  • You don't want a second process, that is different than a thread and doesn't help your situation at all. Creating a `Runnable` in your `onCreate()` doesn't create a thread. One of the more confusing parts about the Android `Service` construct is that it runs in the "background" from the *user's perspective*. That is to say, it is not *visible*. But, its lifecycle callbacks (and in this case the listener callback) are called in the context of your main UI thread. – Larry Schiefer Dec 28 '16 at 14:40
  • Sleep is a larger animal and gets more complicated, particularly starting with Marshmallow. `Service` instances run in the "background" and require no UI. So, for long running operations or things which require no UI it is good. `BroadcastReceiver` similarly runs any time - but, it must be *very* short lived. Both run in the context of your main (UI) thread. – Larry Schiefer Dec 28 '16 at 14:42
  • If you need a thread to handle heavy processing, there are a number of options your `WearableListenerService` or even a `BroadcastReceiver` can use: `Thread`, `ThreadPoolExecutor`, `AsyncTask`, etc. *But, none of these are lifecycle aware so you have to carefully manage them to ensure they do not directly interface with components which no longer exist, retain references to transient objects (like `Service` or `Activity`), or else you can crash or cause memory leaks.* – Larry Schiefer Dec 28 '16 at 14:44
  • Sorry I meant second service not second process. I do not see how my listener callbacks are considered in my main UI thread. If that were true wouldn't i be able to call functions and update interface objects from within my service directly? This is all to handle doing work while phone is asleep. Will the broadcast manager do stuff while phone is asleep if i use it? because i believe i can use broadcast receiver to call functions directly unlike the handler static situation described. but i figure the broadcast receiever shuts down when phone sleeps – John Bravado Dec 28 '16 at 14:52
  • So, the confusing part about this is what you mean by the phone being asleep. If the phone is sleeping, then nothing is running but the cell baseband. Your `BroadcastReceiver` and/or `Service` (and any other component) won't run until the device is awake. Note that awake does not necessarily mean screen on. Also, just because something is executing in your main thread, doesn't mean it can access statics or interface classes - the instances of those things are lifecycle dependent. – Larry Schiefer Dec 28 '16 at 15:16
  • this is what i mean by asleep. I am walking around with phone in pocket every 5-10 minutes i want to use the watch to add a counter. say i am counting people with hats i see walking down the street. after about 2 hours i will pull phone out of pocket and record data in a database. and yes final option would be use service to save to db and then on resume of app reload db data and display. and this may be best solution in the end. i know stuff has to be more active than just cell baseband otherwise my alarms on my clock would not work – John Bravado Dec 28 '16 at 15:23
  • Alarms wake the device at specific times via a special driver in the kernel and support on the hw. They don't "run" while the device is asleep. They wake the device up long enough to execute. It's a subtle, but very important difference. The ops you describe can all be done with the things we have been discussing. Because the device may be in a low power state, you will have to do some things to keep it awake long enough to do your work, if you need to do it right away. Android Wear will only wake it long enough to run your listener. – Larry Schiefer Dec 28 '16 at 15:57
  • So run the listener meaning it completes all functions and stuff associated within the call to the listener onMessageReceived(). so if i send a broadcastreceiver call to the main activity from within that function, will the main activity react? or will the phone go back to sleep before the main activity can react? would i have to enact a partial wakelock in order to process the mainactivity action then release wakelock after complete? Thanks for all this informaiton to it is helping a lot understanding the actual operation for me to program right. – John Bravado Dec 28 '16 at 16:14
  • No, your `Activity` will not run while the device is screen-off and low power. Your `BroadcastReceiver` is a separate component (as is a `Service`). If you need to do file I/O (sqlite db access or otherwise) for your counter, or any CPU intensive work, then have your listener take a partial wake lock and start a secondary service to do the work. `IntentService` is a good option, just be sure to customize it so it releases the wakelock when it is done. If you are supporting API 21+ you could use `JobScheduler` and be more future-proof and efficient. – Larry Schiefer Dec 28 '16 at 16:33
  • Thanks for everything i am going to take this all in and do some work and see what happens. – John Bravado Dec 28 '16 at 16:58
0

I certainly do not want to oversimplify greatly, but I like the easy way. Having intent I just awaken mobile or wearable from Sleep, and then the other threads also perforce awaken and process data.

   @Override
    protected void onHandleIntent(Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.

        String tmp = " ";
        PowerManager.WakeLock wakeLock = null;
       // wakeLock.acquire();
        if (intent.getAction() != null) {
             tmp=intent.getAction();
            PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);

            wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), TAG);
            wakeLock.setReferenceCounted(true);
            if(! wakeLock.isHeld()) {
                wakeLock.acquire();
            }

Code snippet from https://github.com/NickZt/E52/blob/master/wear/src/main/java/ua/zt/mezon/e52/core/MySpcIntentService.java