I have implemented a simple Android Service that, by default, is deployed within the same process as my app / apk. I want the Service running concurrently with each Activity. To make that happen, in each Activity.onStart() and Activity.onStop() implementation, I have logic that invokes Activity.bindService() and Activity.unbindService(), respectively.
Well, all of this works fine, but it feels awkward. Is there any other way to make sure the Service is continuously running and bound to all Activities without having to re-invoke Activity.bindService() and Activity.unbindService() for each Activity? Should the Service in this case be declared as a stand-alone process?
Also, my Service starts a separate thread, but never stops it. Should my code stop the thread? Is there a chance the thread could be orphaned? Starting / stopping the thread with OnUnbind / OnRebind seems like overkill.
Create a base Activity and call bindService in onStart, unbindService in onStop.
public class BaseActivity extends Activity {
#Override
public void onStart() {
// ...
bindService(intent, serviceConnection, flags);
}
#Override
public void onStop() {
// ....
unbindService(serviceConnection);
}
}
This will make sure every activity that extends base is bound to the service.
When last activity is unbound from the service, it will be stopped. If you want to avoid that, call startService first, and then bind to it. This will prevent service from stopping even if you don't have running activities.
Should the Service in this case be declared as a stand-alone process?
In your case, you don't need a separate process for your service.
Also, my Service starts a separate thread, but never stops it. Should my code stop the thread?
If you want to stop your service, you should stop your thread because thread is a GC root, and all objects accessible from it will remain in memory. So, infinite thread that is not used is a memory leak.
You can implement threading different ways depending on your requirements. You can either implement a regular thread in your Service, or a ThreadPoolExecutor or a Handler. Pick a solution that fits to your needs.
You can start your Service in your custom Application class. This way the service will be started only when your application is started.
For example:
public class MainApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
starService();
}
public void starService() {
Intent i = new Intent(this, YourService.class);
this.startService(i);
}
}
While the other answers ere good, you might want to ask this:
"Does this service needs to keep on running while the application is not, and will not run?"
If so: create as an independant serviceIf not: extend a helper class that implements the bind/unbind and have Activities extend that.
Related
In my application i start an service from a activity using startService command. This service is used for uploading file so it will take time.
So what i want is my Activity should be finished and srvice should keep on doing its work. For this purpose after calling startService() i call the activity finish also.
Because of this my service stops in between abruptly while if i dont call finish of activity everytihng works fine. I want to know how to make it possible so that service keep doing its work while Activity (who started this service) is finished.
Thanks in advance for help.
You should do your uploads via IntentService because:
•The Service runs in background but it runs on the Main Thread of the application.
•The IntentService runs on a separate worker thread. so it runs your codes even when your application's Activity isn't open
Use something like this:
package com.example.test;
public class MyService extends IntentService{
public DownloadService(){
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent arg0){
// Here is your codes
}
and here is a good sample ;-)
I have a bindservice in onCreate that takes a long time, I tried to solve this problem by moving it to a worker thread, but it still causes the UI to wait. What can I do
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
new Thread(){
public void run(){
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
Intent serviceIntent = new Intent(getApplicationContext(), Recognizer.class);
bindService(serviceIntent, mConnection,Context.BIND_AUTO_CREATE);
}
}.start();
}
From your description, it seems that calling bindService within UI thread is not the root cause of ANR. You should instead, call bindService without spawning user thread. One main reason is that, this causes memory leak.
When there is configuration change, as long the the thread still alive, it doesn't give chance to Activity for performing garbage collection. This is because your user thread is still holding reference to Activity.
The ANR root cause should come from Recognizer or mConnection. If you can post the implementation details of them, this can help us to help you.
Ask yourself the following questions
Are you performing any I/O intensive task in mConnection's onServiceConnected?
Are you performing any I/O intensive task in Recognizer's onCreate?
...
As others have said, the problem is not in your Activity, but in your Service. Your onBind() call is taking too long and onBind() is called on the main (UI) Thread. You are doing too much work in the onBind() call. What you need to do is to move your initialization of your Service out of the onBind() call and into a separate background thread. To prevent the client from using the Service before it has been initialized, you'll need to keep a flag for each bound client which indicates if the background thread has completed the initalization. If the client tries to use the Service before it is ready (ie: completely initialized) then you can return some error code or throw a suitable exception.
Remember that lifecycle calls in all Android components (Activity, Service, BroadcastReceiver, ContentProvider) all run on the main (UI) thread and must run quickly.
The problem is not in your Activity. You said that your bind service takes long time. So you must create thread inside the onBind method of your service.
public class ClientService extends Service
{
#Override
public IBinder onBind(final Intent intent)
{
new Thread(){
public void run(){
// Your code here
}
}.start();
}
}
I have kind of a tricky situation in my app.
I implemented a mechanism that contacts a remote server every 60 seconds to check if new data is available. If so, the new data is displayed in the app. So far so good.
I implemented the mechanism the following way:
It gets started in the onCreate() method of my MainActivity.
The polling routine gets stopped in my MainActivity's onDestroy() method.
This makes sure the polling is always active as long as the app is running. Also, if I start another Activity from my MainActivity, I also want the polling to run.
My Problem:
When I exit my application via the Back-Button, everything works fine and the polling stops. But when I exit my application through the Home-Button, the polling routine stays alive since onDestroy() of my MainActivity is not called, but I want it to stop.
If I change my code and stop the polling routine in the onPause() method of my MainActivity, I have the problem that the polling also gets stopped when I launch a new Activity.
What I want:
I want the polling to run as long as my Application (not my MainActivity) is in foreground / visible to the user. As soon as the User exits the application by pressing the Home-Button from anywhere in the App, or by pressing the Back-Button from the MainActivity, I want the polling to stop.
ADDITIONAL:
I also do not want to restart and stop the service everytime I switch Activities. Since the user of my Application will switch Activitys very often, this would just be a lot of overhead. Furthermore, I want the "refresh"-cycle to be exactly 60 seconds. I cannot guarantee that when I always restart the service and stop it again. It needs to be started once when the app gets started, and stopped when the app is no longer in foreground.
How to achieve that?
Isn't there some kind of simple way to check when the App is in foreground and when its hidden / closed?
This is my singelton-polling mechanism:
private Timer t;
private static Updater instance;
protected Updater() {
// Exists only to defeat instantiation.
}
public static Updater getInstance() {
if(instance == null) {
instance = new Updater();
}
return instance;
}
public void startPollingRoutine(int interval, int delay) {
t = new Timer();
// Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
update(); // some asynctask that does the updating
}
}, delay, interval);
}
public static void stopPollingRoutine() {
t.cancel();
}
In code:
Updater.getInstance().startPollingRoutine(60000, 0);
Updater.getInstance().stopPollingRoutine();
I think the best way how to handle it is to create some BaseActivity which all activities will extend. And to perform this actions in onResume/onPause. Or you can try using services.
you need to create a service and trigger it in your main class that service will be triggered unless you explicitly stop it on destroy means onBackpressed()/onDetroy() and let it run in onPause() method
Use a singleton, and let it have a counter variable. Increase it when you send intent to start a new activity, and decrease it in the onPause.
Than you can tell if the polling has to stop; when the counter in the singleton is zero.
Thank you all for your help and time.
I finally found a solution by myself that meets all my requirements.
I followed this tutorial to make it work: http://www.mjbshaw.com/2012/12/determining-if-your-android-application.html
The basic Idea is to extend the Application class and keep reference to how many Activitys are "alive" at a certain time.
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
I Need some help here, I have a service which I can start or stop whenever I want and using the onStart() command to pass some extras using putExtras() from my activity
But I need some serious basic instructions on how to interact with the already created service.
Please don't refer me to another webpage which already have some implementations, just give me the needed code to interact from my UI activity to the service:
something like this:
public class myActivity extends Activity {
Object ReceivedObjectFromService;
onCreate()
{
some stuff here
myMethod()
}
public class myMethod()
{
//do some stuff with the ReceivedObjectFromService
//Don't know how to call this method from the service btw
}
please some help, I don't understand the tutorials on how to interact service to activity or viceversa
Interaction with already created service is no different to starting a brand new service. You just simply call startService() so your client code is no different.
Now, the part which is different is the service itself. In your service, onCreate() must start a background thread or a timer to carry on doing a work. onStart() will receive all startService cases and must in fact add the data it receives in the Intent to an internal list or queue and then in the timer's callback start processing from this queue.
Now you can pass any messages or data you want (even closing the service) using startService and passing data in the Intent that your service understands.
Hope this helps.