android service with multiple listeners - android

I am having some trouble creating a NON-IPC service that allows adding/removing multiple listeners at various times, for example, I would like to be able to contact the service and "subscribe" to its events any time, or "unsubscribe" from it. The service wakes up every once in a while and sends an event to all subscribed listeners.
I have been looking at stackoverflow examples, googling, etc, particularly I found something similar here:
android restful api
In that example, the suggestion is to use ResultReceiver to serve as a callback from a service. But in this approach, doesn't it mean that the service can only notify listeners sent to it as part of the first intent (i.e I cannot add/remove listeners whenever I want)?
Also, in that example, what happens if the activity gets destroyed by the OS for some reason, but the service still has a reference to the listener and tries to invoke it? The listener will try to perform some action on the activity, which no longer exists, right?
Maybe I am missing something... I'd appreciate some input if possible..
Tnx

First, 'sleeping' services are anti-pattern in Android. If you need to do something periodically, start your service using AlarmManager. Second, the service can be restarted at any time, so you cannot rely on 'subscribing' where you keep references to other components (activities mostly). If you need to send a notification to multiple activities, use a broadcast receiver. Activities can register for it statically (using AndroidManifest.xml), or dynamically (with code).

Related

Android controlling service with different applications

I have an app with an auto log out feature where I was using a Timer to auto log out the user (where user is a static singleton object).
Recently I realized there were some other activities and I have to implement a global log out feature so I tried to implement different Timers to each Activities and tried to synchronize them, but it wasn't a good approach and it was a pain. Then I turned my face to the services.
What I need to know is a good way to control a single service within different applications. Any ideas will be appreciated.
You can implement bound service, start it, and bind it with two activities.
More information You can find in official developer docs this and this
you can implement a "Bound" service to interact it from different activities.
Here is complete example for Bound service with explanation.
http://developer.android.com/guide/components/bound-services.html
A broadcast is a message that any app can receive. The system delivers
various broadcasts for system events, such as when the system boots up
or the device starts charging. You can deliver a broadcast to other
apps by passing an Intent to sendBroadcast(), sendOrderedBroadcast(),
or sendStickyBroadcast().
All that you need to do is to create BroadcastReceiver. Add IntentFilter for it. Register it in your Service. And than send Intent with action that you add to IntentFilter from any of your Applications.
Go throw this article to get better understanding of Intents

Why the receiver defined in manifest is not receiving broadcasts when used with LocalBroadcastManager?

Few days ago I read that there is a better mechanism for sending broadcasts within single application - the LocalBroadcastManager.
It works well (just like standard broadcasts..). However, yesterday I've found out that it cannot send broadcasts to receivers, which are defined in the manifest (when I temporarily switched it to use the standard Activity's sendBroadcast method, it worked).
The reason why I want this (and correct me if there is a more preferred way to do it) is:
Lets's say I want to download a file. I will use a service, because that's how Android wants us to do. OK, now I want to display (and periodically update) its progress in my activity. So service will be sending broadcasts to my activity and the activity has to register to receive them. The preferred way to handle broadcasts is to register in onResume() and unregister in onPause(). Now let's imagine that the user is bored with the slowly moving progressbar, so he presses Home and goes to do something else. Later he comes back and wants to see the current status of the download, but how can I tell him, when I unregistered from broadcasts that second he left my application?
That's why I use a receiver defined in the manifest, to be always ready to receive the broadcast and store it permanently (shared preferences, database...), so the activity can reconstruct the latest broadcast when it becomes visible.
However now I'm not sure, whether this routine is not recommended, or why the LocalBroadcastManager is not allowing me to do it.
If you are using SharedPreferences a workaround would be to make your activity implement OnSharedPreferenceChangeListener. So the service writes the pref and the activity listens for the change and updates progress bar. onResume() you also check the preference and update the UI accordingly.
The nice thing with this is you don't really have a leak if you fail to unregister them - see
Android : Where should a OnSharedPreferenceChangeListener be defined/registered - I prefer to unregister to onDestroy() as I want to have my activity updated even if not in the foreground - and the listener will go away even if onDestroy is not called.
As for why it does not work with manifest registered receivers - could you post some code ? Do you actually register the receivers with LBM ?

Android: Regular UI Updates & Communication Service <-> Activity

So what I'm trying to do is just updating an activity's views in intervals like, say, once per second. In this specific case a handful of buttons, and all I want to change is their text. I've read quite a few questions here addressing the same problem, but I seem to be stuck a little more than other people, and I'm going to blame that on my restricted experience with Android (which actually means, I did not understand the solutions proposed, or was unable to identify the core ideas in the sample code, and that this is actually the first time I'm trying to program for Android).
Since I would like a service to own the data (and its creation), I thought of a callback to the activity, and that's what I've been trying got get my head around for the past few hours. What I do have is a service with onCreate(), onStartCommand() and onDestroy() and basically, that's fine. I registered it in the android manifest file, and succeeded at bringing it to life (I'm logging the lifecycle methods).
But how do I get to
have the Views updated frequently with the data from the service
give the service certain information it depends on (like notifying it of a button event)
Thanks for your help!
Read about Binding to a Service from the official Android docs.
It should answer all of your questions.
Basically, the idea is that you "bind" to a service, and doing that gives you the service object. From there, you can just call the service's methods directly. In your case, you'd probably want a method declared in your service called notifyButton1Pressed() or something similar.
To refresh the Activity's views in an interval, use a TimerTask and a Timer. Those are pretty self-explanatory if you research them via Google.
In order to update your activity from service, you have to register an BroadcastReceiver in your activity. In the receiver you do your update, and in the service, you have to sendBroadcast to your activity. And information between activity and service you could send through Intent which is sent by sendBroadcast.
There is actually a pretty simple way to update an activity from within itself using a Timer and a android.os.Handler. The idea is to give the activity an interface (e.g. IUpdateable) that exposes an update method. Then extend the TimerTask to take (Handler, IUpdateable) as arguments and keep references to it. In the TimerTask's run() method, call e.g. updateableActivity.update(). In the activity, instantiate a Timer and schedule new UpdateTask(new Handler(), this);.
This way you have an actually reusable approach (using an interface makes this easy to implement in any activity). If this was unclear, have a look at this gist.

Design suggestion required

I want to create an application in which
- Create a listener which listens for outgoing/incoming messages and calls
- UI is shown/hide based on listener results
Shrini,
As dds stated, you will definitely need at least two BroadcastReceivers. You will need one BroadcastReceiver for each incoming call and message that you want to respond to, and one for each outgoing one as well. A BroadcastReceiver may only capture one BroadcastMessage at a time. You will specifically need to capture the Intents sent by the operating system and your Application will need to have the appropriate Permissions for each. That's just setting up the listeners.
Once the BroadcastReceiver has been called you will need to start an Activity for you UI and possibly a Service to do any other processing. In the cases of single-point events (like messages) an Activity is often enough. Calls, however, depend largely upon what you are doing. Since a call has two distinct events, in order to tie them together, many people prefer to use a Service just to hold and watch the call.
In order to best help you, I must inform you that your question is remarkably vague as to what you need to do. Does your custom UI display information about the calls? Does it allow the User to respond or change that information? What kind of messages is your app responding to? SMS? Email? IMs? These are important because each one has different considerations.
Given that the limitation of information provided here, I would recommend researching your topic by downloading and viewing some of the open source projects stored on Google. Here is a Here.
Fuzzical Logic
Create a listener which listens for
outgoing/incoming messages and calls -
UI
To achieve this I think you need to use broadcast receivers to catch the broadcast message when any message activity is going on. You may need 2 in BroadcastReceivers , one for incoming and one for outgoing messages.
In the receivers you need to call your related Activity (your UI) to interact with the user. But note that you should not do any time consuming work in BroadcastReceiver since in BroadcastReceivers are expected to be light weight and killed in 10 seconds after they are invoked. See Broadcast receivers at here

Activity as a listener and memory leaks

I have the following framework for my application:
1. a Network thread that runs in the background (a queue) for issuing request and get async responses. The thread is started and stopped in the Application Object so it's leaving through out the whole application.
2. a DataManager which is also a member of Application and has different DataManagers for the data types i retrieve from the network. the data manager itself is the listener for the responses from the network so it's safe until the application itself dies.
3. this is the problematic part. Some of my Adapters and part of my Activities are DataListeners for my DataManagers, that means that the data manager keeps a reference to them.
When a phone call or some other phone event occurs i've noticed that the activity is usually in paused and not destroyed and so receives my events, which is ok. the problem starts when landscape\portrait is changed. since i keep a referenced to the activity in an Application bound object, the activity can't be destroyed on one hand, BUT the event is still getting to the listener, only the wrong one...
Basically i can fix that issue by removing the listener in onDestroy and retaining configuration boolean to tell me that request was allready issues and i just need to put a listener and try to retrieve the data from the data manager.
However :-) i was wondering how android handles this cases usually, if for example this was a Service running. or if the Service is a local Service that used Bound and passed on the Activity as a Listener to the network Event, the same things happen, untill the listener is not removed the Activity is leaked and lives on, but without it, no way to get callbacks from the network...
an Intent requires serilaztion and deserilazation of data which can be heavy (Bitmaps for example?)
And anywa, asuming i send an intent on each respose i get, how do i get the intent to the Activity (i know of getIntent, but if i get another one , not related, do i get it as an 'event' ?)
From what I gather it's customary on Android to remove yourself from listener lists when the activity is destroyed. It's kinda error-prone, but I think it's the generally accepted way to do it.
You could imagine your service accepts only one listener, which may or may not fit your case, and when the activity restarts its registering with the DataManager would overwrite the old activity which would in turn be garbage collected. The drawback is, you don't free the activity memory if it is destroyed but the service lives on, so it's probably better to just remove the activity from listeners.
Android development is rather different from other platforms (e.g. BlackBerry). I'm not able to give you a quick silver bullet solution, however here are my thoughts on this:
Some of my Adapters and part of my
Activities are DataListeners for my
DataManagers, that means that the data
manager keeps a reference to them.
OS kills Activities according to their lifecycle. So you should avoid keeping a handle to an Activity in another object which is supposed to live after the Activity is destroyed by OS. Otherwise you'll get memory leak.
Also keep in mind Application sublass instance does not always live for the whole application session (a session from a user perspective). If your app goes in the background, for example, due to an incoming phone call, then your entire process can be killed. See details here. As soon as you Application sublass contains some state which is not persisted if process is killed you may mistakenly expect your handles to point to some non-null entities. However after going to foreground (and process restore) those may just be nulls because a new instance of Application sublass has been created by OS.
Ok, so let me describe the problem and the solution i found in more details.
The problem:
I have a Service\Network Thread that needs to notify Activities that sent requests through it that either request or Error has arrived in an Async way. Using Listener Pattern requires me to set listener before or when i send a request like so:
mNetService.setRequest(request, this);
where this is Activity that implements my listener Interface.
But doing it this way requires me to remove the listener from the service in onDestroy and returning the listener, if i ever sent a request back in onCreate\onResume, but the response can also arrive exactly when the activity is not listening (landscape\portrait event) which requires me to keep the Error\Response in the service until some1 picks it up and resets it.
The solution i found:
using Broadcasts and BroadcastReciever.
this is only part of the solution but it let you have a listener to broadcasts (that can be specific for a certain class type meaning Activity) and action.
Since all of my Activities inherit a base Activity class i've made they all have a BroadcaseReciever inner class that listens on certain action in it's filter.
is i enable the listening in the C'tor of my Activity the listener will be registered in onResume and deregister in onPause.
If the listener gets onRecieved event it will call a method in the Activity (which i can override in my specific activty) and pass it the Intent i got which can contain all the data from the response.
The only missing part is what happens if the Activity dies for a second and only then the broadcast arrives ? ah, that's a problem, so android intorduces Sticky Broadcasts that stays there untill you remove them with removeStickyBroadcast(Intent), so when is ent broadcast from my service i send Sticky broadcast, when the Activity gets my Broadcast it removes it so it wont stay around and mislead the activity about new response that arrived.
The only problem with it is if i send a request, don't wait for the response and goes to the next Activity right away, in this case when i'll go back to that Activity it will think it got the response. Didn't find a proper solution to that just yet. But it's better then my previous solution.

Categories

Resources