I want to start a Service for a long running location fetching task.
I've chosen to use a foreground service for this task. I want this service to run in the background thread.
Now, after searching a bit, I have decided to start a new thread in onStart() of the Service and not the Activity itself. I don't want any memory leaks with the Thread having reference of Activity. I am fine with Activity being destroyed.
My question is, on which Thread is onStartCommand() is called? What will happen when I try to start the Service again?
I am not very experienced when it comes to threading, please point out anything I'm missing or am wrong about.
onStartCommand is always called on the main thread. If you want to run code on another thread, you must create it in your Service. Services by default do not create a Thread (exception: an IntentService will create a thread, and call onHandleIntent from that thread).
Only one instance of a Service exists at a time. Starting it again will not create a new Service object, but it will call onStartCommand again with the new intent. If you do not wish two threads to be created, you must prevent it yourself. Generally by keeping a reference to the thread and not creating it if not null.
Related
I have seen some postings on this subject, but none of them have satisfactory answers.
Assume that I start a worker thread from my main (one-and-only) Activity, in its onCreate() method. Then I call finish() to cause the Activity to terminate.
At that point, the task it belongs to gets destroyed (since there are no longer any Activity in it). The app (and the process running it) may continue to exist, however, in empty "skeleton" form, so that it can be restarted quickly if desired (although it would be highly susceptible to being killed by the system).
Assuming the above is correct -- when is the worker thread killed? Is it only killed when the system actively destroys the process?
In my case, my worker thread exists as a listener for a Bluetooth connection; when received, it will fire up the desired Activity again. In this situation there is no actively running component (Activity, Service, ContentProvider or BroadcastReceiver). It seems to me that this should work, except that something is killing my worker thread.
I am aware that I could do this (and with less pain) by using a background Service. However, I'm curious about why this isn't working.
Thanks,
Barry
when is the worker thread killed? Is it only killed when the system actively destroys the process?
-> the worker thread is skilled after all its code in run function executed. It still run even when your activity is destroyed.
In my case, my worker thread exists as a listener for a Bluetooth connection; when received, it will fire up the desired Activity again. In this situation there is no actively running component (Activity, Service, ContentProvider or BroadcastReceiver). It seems to me that this should work, except that something is killing my worker thread.
To make it works, You need to have a background service in this case and make a soft/weak reference to your service from your worker thread or more simple, using EventBus to start any component from your Service as:
EventBus.getDefault().post(new BlueToothEvent()); // call in your worker thread
// do something in your service
onBlueToothEventFired(BlueToothEvent e);
Android App lifecycle has a nice example that is very on topic:
A common example of a process life-cycle bug is a BroadcastReceiver
that starts a thread when it receives an Intent in its
BroadcastReceiver.onReceive() method, and then returns from the
function. Once it returns, the system considers the BroadcastReceiver
to be no longer active, and thus, its hosting process no longer needed
(unless other application components are active in it). So, the system
may kill the process at any time to reclaim memory, and in doing so,
it terminates the spawned thread running in the process.
In short, its really not very predictable if you thread would get a chance to run until termination or process will be killed beforehand, you should NOT definitely rely on any order/behavior.
Worth mentioning separately that its fairly easy to leak your activity along with thread even if you finish() it, but if its your last/only activity it does not change the picture
When you start a thread, it is independent of the parent that started it. In your case, it is your application activity. This means that until the Run method has been fully executed, your thread will live.
If you exit the application (and therefore call the activity's onStop method), the thread will still exist, and you will cause a memory leak. It will eventually get killed by the system if you run out of memory.
Since you mentioned that you created a listener to listen for a Bluetooth connection, your thread probably dies before it receives any event (It is impossible for me to know without any code snippet). It might also crash which would be ending the thread.
There is one main (also called UI) thread in Android. That is the only thread your app uses, unless it starts one explicitly via Thread.start(), AsyncTask.execute() etc. All Activities, Services, BroadcastReceivers, etc run all of their lifecycle methods on that main thread. Notice I included Services- a Service runs on the main thread unless it starts its own Thread (the exception to that is an IntentService, which does run on its own Thread).
A Thread you create continues until the Runnable its passed returns from its run function (or of course the process is terminated). This can live past the end of the Activity/Service it was created by. However such a Thread would still live in the original instance of the component, and would not be able to access variables of a new instance if one was restarted without a lot of special work (see Loader pattern).
IntentService has its own thread, starting another thread from handleIntent, the service considered live or completed service and doesn't matter another thread is active or nor?
and as soon as the IntentService completed its job ,is it possible to return to main thread and call another thread, but the start of the another thread could be from main thread not from activity, as the service could complete its job during any active activity.
IntentService has its own thread, starting another thread from
handleIntent
Don't ever do that. Once the IntentService's onHandleIntent() method returns, the service is destroyed and the process is likely to be killed as well. Android has no idea what threads you've started so for all it knows your process is idle and wasting resources.
If you need to "start" something else when the IntentService is done, use startActivity(), startService() or sendBroadcast() (whichever is appropriate). Again, Android doesn't know about your threads.
If you need procedure call semantics (e.g, start service, have it perform some task, then return control to the caller), IntentService isn't the right tool. Use a bound service (or bound AIDL service if you need to cross process boundaries).
I have a Service where I run a task inside a Thread. I call this Service many times and obviously it creates the corresponding number of Threads.
How am I going to know when no one Thread is running so I can call stopSelf() ?
The easiest thing to do is make your service subclass IntentService. This is a special kind of Service that will perform work in a background thread, and automatically stop the service when there is no more work to perform. There is a single thread per Service that you declare in your manifest. All you do is determine what sort of work you want to perform by implementing its onHandleIntent(), which is automatically run in that background thread for each Intent delivered to it.
You can keep track of the running threads in an array. When each thread completes it should remove itself from the array and call a method that checks if there are any running threads. That method just checks if the list of running threads is empty, and if so, calls stopSelf().
Or use IntentService if this suits your needs.
In android A service runs in the main thread of its hosting process, I want to know that if I want to create my own thread, then where to create it, Inside service class or Inside the activity form where we give call to the service ..?
thanks in advance
Generally, if you need your thread to persist after your activity is gone, then you need to run it in a service. The point of a service is to persist beyond the life of an activity.
Passing data across activities, services and threads may complicate the answer, and so you may end up running a thread in a service even if the thread does not persist after the activity, but that is a rare case.
Your activity should start your service, then start your thread inside the service. If you put your service launching code in a thread, all that would do is start the thread in the background but the service (and consequently the code you want to run in the background) would still run on the Main thread
If your aren't trying do some continuously running task, I would suggest using an IntentService. With an IntentService all most of the thread handling and the service cleanup is done for you.
I created a service (service B) from Activity (Activity A). And from service B, i created another service (service C). previously the service C used to be a thread not a service. Since it has problems in the long run i changed it to a service. The service C runs a while loop with 3 second Thread.sleep calls. But general condition it do not stop. The Log shows the service is running. But the UI is blocked and after few mins system ask me whether to shut down.
How to make this service non blocking call?
From the service documentation in Android
A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
The best way in this case is to start a new thread and then call a service from there.
Yes, from the documentation, it's clear that services are not separate processes.
Instead, please follow below to make it work:
Start a service from wherever you want to start
In service's class you wrote, write another private class extending thread which will make sure all your background stuff will run in a background thread which is separate from a mail process
Start a thread from onCreate method of service's class. If you start your background work in onStartCommand, you may accidentally start multiple services doing the same task.
Ex. You've given a button on your activity which will start background service. And if you happen to click it multiple times, it'll start those many number of services in background.
Thus, if you use override onCreate method from service, it will check if the service is already running or not and if it's not running, it'll start the service. Otherwise it'll skip and won't start another service.
I think that service C is running on main thread, try create another thread (new thread or asynctask)
Services always run on the main thread.
You need to spawn a background thread or repeatedly run a TimerTask etc in your Service C to avoid blocking the UI thread.
You can start your service in a separate thread like so:
Thread newThread = new Thread(){
Intent serviceIntent = new Intent(getApplicationContext(), YourService.class);
getApplicationContext().startService(serviceIntent);
};
newThread.start();
Please refer to this comment.