Android Activity to Service Connection - android

Activities have handler methods on them like onClick for various UI events. How does one guarantee that the service connection exists for these methods? The service connection has an onServiceConnected method for initialization after the service has connected. However this seems like not the best place for UI initialization. I want to avoid onClick(View v) { service.getValue() } from being a null service reference. On the other hand I don't want the UI rendering to depend on waiting for a service reference. It seems that onCreate() is the right place for setContentView() etc. On the other hand onCreate is initializing handlers which might not be using a valid service reference yet. How does one guarantee that a service reference is valid for UI handler methods. Or is this a good reason not to use a service reference at all? Whats the best practice here?

You have to signal to the Activity that Service is ready.
The simplest way would be to set a flag e.g. serviceAvailable = true, in ServiceConnection.onServiceConnected(). Then every time you need service you check this flag.

In the UI event listener, you could check if the service reference is null before using it:
if (service != null)
{
service.getValue();
}

Related

find android thread after app quits

If I leave a thread running when I quit my android app, can I get access to that thread when the app is restarted? I know that the thread is still associated with my app because I can kill it by going to settings-apps-force stop.
more details: my app connects to a device via bluetooth. when i rotate the tablet, it restarts the app, but if i don't stop all the threads, the old thread reconnects to the device and the app is not able to connect with a new thread.
I have fixed the basic problem by not allowing the app screen to rotate, and by killing the connect thread onDestroy(). but I would like to know how to re-connect with that sort of zombie thread just out of curiosity.
I can see threads that I don't recognize in Thread.enumerate(), but I don't know how to get access to those threads, other than seeing the name and their state.
The way I deal with this in my apps is to override an Activity's onRetainCustomNonConfigurationInstance() method, which allows you to retain an object through the restart that happens when the screen is rotated. Here's how I implement it.
I have an AsyncTask that performs a web request. The AsyncTask is in a separate file, and takes a reference to the calling Activity as a listener for some callbacks I have implemented. So the constructor for my web request AsyncTask is something like this:
private Callbacks listener;
public WebRequest(Callbacks listener) {
this.listener = listener;
}
I implement onRetainCustomNonConfigurationInstance() in my Activity like this:
#Override
public Object onRetainCustomNonConfigurationInstance() {
if(webRequest != null) {
webRequest.detachFromActivity();
return webRequest;
} else {
return null;
}
}
Now, when my screen is rotated, the Activity restarts, and if my AsyncTask is running, it will save a reference to it here. Notice that I also "detach" my task from this current Activity, which will now be destroyed. I accomplish this in my task by just making the listener (which is the current Activity) null. Like this:
public void detachFromActivity() {
listener = null;
}
Now when the Activity restarts, in onCreate(), I check to see if there was a retained reference to my running thread by calling getLastCustomNonConfigurationInstance() like this:
Object retainedRequest = getLastCustomNonConfigurationInstance();
if(retainedRequest != null) {
if(retainedRequest instanceof WebRequest) {
webRequest = (WebRequest) retainedRequest;
webRequest.setListener(this);
}
}
Since the reference to my running thread is passed as an Object, I need to retrieve it as an Object, then check if it's an instance of my AsyncTask, then cast it if it is.
The last step is to "reconnect" the callbacks to this NEW Activity, which was just created, so the task knows where to send the results. I use the setListener(this) method to do it in my task, like this:
public void setListener(Callbacks listener) {
this.listener = listener;
}
Now I can re-attach a reference to an old thread with a newly re-created Activity. You may not be using an AsyncTask, but the concept is the same and should work for any Thread, or any object you want, really.
Hope this helps!
Im not sure on your question, but what you are doing is kinda wrong. Screen rotation are UI changes and they should not affect your other code.
Check this answer for some guidance- http://stackoverflow.com/questions/5913130/dont-reload-application-when-orientation-changes
PS: NoChinDeluxes answer is also good for decoupling UI with other elements
The basic problem, as you have discovered, is that you have implemented your app in such a way that your bluetooth connection is logically bound to an Activity (i.e. the Activity is responsible for keeping track of the thread handling bluetooth activity).
To have the bluetooth connection reference survive a rotation, you will need to decouple it from the Activity. There are a number of ways to do this, depending on exactly what your requirements are.
You could, for instance, implement the bluetooth code as a Service.
There are other ways as well - for instance, take a look at Activity restart on rotation Android

Android onCreate or onStartCommand for starting service

Usually when I create an Android service I implement the onCreate method, but in my last project this does not work. I tried implementing onStartCommand, and this seems to work.
The question is: when I have to implement a service which method is required? Which methods I have to implement? onCreate, onStartCommand, or both? And what is the role of each?
onCreate() is called when the Service object is instantiated (ie: when the service is created). You should do things in this method that you need to do only once (ie: initialize some variables, etc.). onCreate() will only ever be called once per instantiated object.
You only need to implement onCreate() if you actually want/need to initialize something only once.
onStartCommand() is called every time a client starts the service using startService(Intent intent). This means that onStartCommand() can get called multiple times. You should do the things in this method that are needed each time a client requests something from your service. This depends a lot on what your service does and how it communicates with the clients (and vice-versa).
If you don't implement onStartCommand() then you won't be able to get any information from the Intent that the client passes to onStartCommand() and your service might not be able to do any useful work.
Service behave same like Activity Whatever you want to associate once with a service will go in onCreate like initialization
and whenever the service is called using startService. onStartCommand will be called. and you can pass any action to perform . like for a music player , You can play ,pause,stop using action
And you do any operation in service by sending an action and receiving it on onStartCommand
onCreate work like a Constructor.
Edit in Short
onCreate() calls only for the first time you start a Service Whereas onStartCommand() calls everytime you call the startService again. It let you set an action like play,stop,pause music.
public void onStartCommand()
{
if(intent.getAction.equals("any.play")
{
//play song
}
else if(intent.getAction.equals("any.stop")
{}
}

Android: How to backup a database when the application gets closed?

I am needing help to determine the right approach. I want to make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed. I want to call this method from a central class called Main which extends Application. The reason for that is, that I need to use several activites and I want to call the backup Method only when needed (like described when the whole application gets destroyed or interrupted by another application). I try to avoid calling this backup method in every activity in their onPause() methods.
I thought about starting a service in the onCreate() method of the application, and starting the backup method when the service gets destroyed. But this won't help in the case of an interrupt, as far as I understood the logic behind services. And also the service doesn't seem to start. startService(new Intent(getApplicationContext(), BackupService.class)); Furthermore I don't think it is a good approach to just use the onDestroy() method of a service, this is not what the service class is made for in my opinion.
So summarizing my Question, do you know a better way then using a service, or if not do you know how I should use the service to be able to call a backup only at the point when the whole app (and not only an activity) is interrupted or destroyed.
First of all, if your service "doesn't seem to start", you are probably doing something wrong.
To accomplish your goal make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed:
There are three cases in general here.
If you want to do it in the activity layer:
To know when your application is crashed, you need to implement a custom handler to catch the uncaught exceptions.
To know when your activity is "interrupted", the only way is do it in onPause.
To know when your activity is "terminated", the only way is to do it in onDestroy.
This will require you to have a clear navigation and only do it in your "main activity", and all the other activity starts and comes back to it OR use a flag to indicate if the pause was caused by going to another activity.
If you want to do it in the service layer: (Your way of doing it onDestroy won't allow you to detect interrupted case since you will have to start service sticky to keep it running)
You will have to set up a flag on each activity onBind (you will have to bind it and unbind it) to know if it is a crash/interrupt/termination, which will complicate other part of your code.
To avoid running repetitive code, you will have to create a generic base class and extend your other activities from it.
I use this approach to play background music in one of my games, but I guess it works in this scenario as well.
Use a boolean flag to indicate whether or not your app is launching another part of your app.
boolean movingInApp = false;
....
movingInApp = true;
Intent intent...
.....
public void onPause() {
if(!movingInApp) {
//start service
}
}
public void onResume() {
movingInApp = false;
//Stop service
}
By setting the value of movingInApp to true before launching any intent etc, you can prevent your app from starting the service. Remember to set it to false again later in your onResume() method. If the system makes your app go to the background, this will be false, and your service will be started.
Why dont u have all of your activities extend a base activity which in turn extend the android activity class
I the base activity have backupDB method in the onPause
Therefore u dont have to put it in every activity pause method

Posting on the UI thread from a singleton manager class

I have a singleton manager class that is called from Activities (UI thread), then it operates on a different thread (Network) and in the it end should call a callback method in the calling Activity.
I was wondering what is the best way to call the callback methods on the UI thread.
I an familiar with the options (see http://android-developers.blogspot.co.il/2009/05/painless-threading.html)
So I was thinking of two options:
the first:
The calling Activities will implement an Interface with a getActivity() method. that method will be used to call Activity.runOnUiThread(Runnable).
the second:
MainApplication, which inits the manager singleton, will pass a Handler instance that belongs to the UI thread.
What is the better option?
I'm also happy to hear any other suggestions
Regardless of what option you choose, you have to keep in mind that the activities have a certain lifecycle, and unlike your singleton class can be finished or moved to the background. In light of this, you should consider again whether singleton is really the best choice here: if it needs to interact with an activity, maybe the activity should manage its lifecycle. If it doesn't depend on any particular activity, you might want to make it a service and send out broadcasts to notify about progress, etc.
What exactly are you trying to do?

Avoid Service callback when Activity gets closed and re-opened

I have a LocalService that exposes a Binder with some APIs. I create a Service Listener, just like this:
if (dataServiceListener == null) {
dataServiceListener = new DataServiceListener();
mainActivity.getApplicationContext().bindService
(new Intent(mainActivity, LocalService.class),
dataServiceListener.svcConn, mainActivity.BIND_AUTO_CREATE);
}
After I call the method that the Binder in dataServiceListener exposes, I get the response in the dataServiceListener onResult() method. Up to this point, no kind of issues, everything is working.
Some sort of problem occurs when I close the Activity that is waiting for the Service Listener callback and immediately reopen it. Even though I re-instantiate the dataServiceListener in onCreate(), I get two callbacks instead of one, the old one from the destroyed Activity and the latter (right) one; this way the results mix up on the UI.
Is there a way to tell the Service or the Service Listener that when the activity finishes, the callbacks must be avoided. Or maybe even destroy the ServiceListener objects.
I think this is the issue that Mark L. Murphy (Commonsware) described in "The Busy Coder's Guide to Android Development":
The biggest catch is to make sure that the activity retracts the listeners when it is done.
How can I do this? Is there a way to get rid of the useless listeners when the activity finishes?
Thank you!
I had the same issue. I was working in a remote sevice using AIDL. I got this problem when i am trying do unregister my listeners using the remove method from ArrayList Collection inside a foreach loop, because I was not using asBinder in the comparision. Searching fora solution, I find out the RemoteCallbackList class in Android API. This class does exactly what i needed, and what i think you should do, on a easy way, taken all reponsabilites for the hard work that involves this task.
From the Android API:
To use this class, simply create a single instance along with your service, and call its register(E) and unregister(E) methods as client register and unregister with your service. To call back on to the registered clients, use beginBroadcast(), getBroadcastItem(int), and finishBroadcast().
Broadcast sample:
int i = callbacks.beginBroadcast();
while (i > 0) {
i--;
try {
callbacks.getBroadcastItem(i).somethingHappened();
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
callbacks.finishBroadcast();
The code you show is for binding to a service. You do not show where you are registering a listener with that service. You apparently are, based upon your question and your reference to an onResult() method. Given the nature of your problem, I am going to guess that what you're doing is:
Binding to the service in onCreate()
In onServiceConnected(), you are calling some sort of setListener() method on the Binder
In that case, if we ignore configuration changes, the proper way to unwind matters would be to, in onDestroy(), call some removeListener() method on the Binder, then call unbindService().
Configuration changes, particularly in a pre-fragment world, make this complicated. It's the reason why this sample project (and the accompanying material in the book) is so icky. Binding is twitchy -- if you unbind from the old activity, and nothing else is keeping the service around, the service will shut down before the new activity gets a chance to bind. Binding is also state -- you cannot simply fail to unbind, lest you leak stuff.
So, the recipe becomes:
Bind to the service in onCreate() using the Application Context
In onServiceConnected(), call sort of setListener() method on the Binder
In onRetainNonConfigurationInstance(), make note of the fact that you're undergoing a configuration change, and return some Object that has your Binder, your Listener, and all the rest of your state
In onCreate(), use getLastNonConfigurationInstance() -- if it is null, proceed as normal, but if it is not null, hold onto that Binder and Listener and don't re-bind and re-register the listener
In onDestroy(), if the flag from Step #3 above is false (i.e., we are not undergoing a configuration change), call some removeListener() method on the Binder, then call unbindService().
Using fragments with setRetainInstance(true) can probably simplify this some, though I have not worked through a sample for that yet.
I had this issue too. You need to release all the resources,listeners,threads from the service when it finishes.
Your activity has to register/unregister itself as the listener. You need to use the proper lifecycle callback methods, not onBackPressed(). Register onStart(), unregister onStop(). One way to do it is to make the listener a static member of your service, and provide static register/unregister methods. Then call those from your activity as appropriate.
I finally solved the issue (and no, I haven't been working on it for so long :D).
The callback to the listener was made before the Fragment's onDestroy was called. So the boolean "dontupdate" value was never set to false. Overriding onBackPressed in the main activity solved the problem, as I invoked a destroy() method for each fragment that takes care of setting the boolean value to false.

Categories

Resources