I want to collect accelerometer data with my app. Therefore I created a service, so the app collects the data in the background, even when the app is no longer open.
Problem is, that when I close the app, the service gets terminated as well and restarts. During that time it won't collect data.
I tried both START_REDELIVER_INTENT and START_STICKY, both with the same result: when the app closes, the service restarts.
Is there way to prevent the service completely from stopping when the app is terminated?
Note that my service is running in a separate process.
Here is my code:
#Override
public void onCreate() {
// start thread
HandlerThread thread = new HandlerThread("SensorData", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
looper = thread.getLooper();
handler = new BGHndlr(looper);
sensorMngr = (SensorManager) getSystemService(SENSOR_SERVICE);
reader = new SensorReader(sensorMngr);
accSensor = reader.getSingleSensorOfType(Sensor.TYPE_ACCELEROMETER);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message message = handler.obtainMessage();
message.arg1 = startId;
handler.sendMessage(message);
return START_REDELIVER_INTENT;
}
Nested class:
public class BGHndlr extends Handler implements SensorEventListener {
public BGHndlr(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
oSensorManager.registerListener(this, oAcceleroMeter, SensorManager.SENSOR_DELAY_FASTEST);
}
//int i = 0;
#Override
public void onSensorChanged(SensorEvent event) {
// do something
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {}
}
both with the same result: when the app closes, the service restarts.
This is a normal Android behavior, there is nothing an Android application developer can do about it.
Note that my service is running in a separate process.
Same as before (all in your question proves it)... That said, the answer to
Is there way to prevent the service completely from stopping when the app is terminated?
is No. You, as others, should stick to the Android components' lifecycle.
Related
I want to show local notification in an Android app that i am working. notification are based on network transaction completed in background.
I have tried service, intent service, jobservice etc but nothing is working when the app is closed.please share some working code for the reference.....
//Here is my service----
public class JobSyncFAQ extends Service {
private Message msg;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
public JobSyncFAQ() {
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// here is my stuff
stopSelf(msg.arg1);
}
}
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("JobSyncFAQ", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mServiceHandler.removeCallbacks(mServiceLooper.getThread());
mServiceLooper.quit();
Intent intent = new Intent(getApplicationContext(),JobSyncFAQ.class);
sendBroadcast(intent);
}
//and in my receiver
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, JobSyncFAQ.class));
}
please note - i am facing this issue only for N+ version
When you "close" your app (i. e. you swipe it away on the recent apps screen), you don't actually close the app, you only close the underlying activity. In most cases, this corresponds to the app being closed, but if you have a background service running, the service is not terminated. This is for a good reason: YOu still want to receive WhatsApp messages, even when WhatsApp is closed. Hence, WhatsApp starts a background service to check for new messages, even when the app is closed.
For that reason, you need to notify your background service about the fact that it should cancel its task.
I developed a media application that uses a MediaBrowserService which is connected to a MediaController. Therefore, I can do the following in my activities onDestroyMethod:
MediaControllerCompat mediaControllerCompat = MediaControllerCompat.getMediaController(getActivity());
if (mediaControllerCompat != null)
mediaControllerCompat.getTransportControls().stop();
This tells the MediaBrowserService to stop and quit.
Edit: Since you use a generic service, you need to call stopService:
stopService(new Intent(MyActivity.this, JobSyncFAQ.class));
Im trying to achive, that my service downloads information and fills a database with that information in the background.
SOLUTION (Using foreground service, code is now the edited-version)
Thats the service:
public class UnitPullService extends Service {
private final static String name = UnitPullService.class.getSimpleName();
public static Boolean isRunning = false;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
try {
UnitDataSource unitdataSource = new UnitDataSource(getApplicationContext());
unitdataSource.fillTables();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor spEitor = sharedPreferences.edit();
// disables the button which starts this service
spEitor.putBoolean("isFilled", true);
spEitor.commit();
} catch (JSONException e) {
e.printStackTrace();
}
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// PART OF THE SOLUTION
startForeground(1000, new Notification());
Toast.makeText(this, "service starting",
Toast.LENGTH_SHORT).show();
// to check if the service is currently running
isRunning = true;
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_REDELIVER_INTENT;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
And thats the intent in the activity (actually from a fragment):
Intent i= new Intent(getContext(), UnitPullService.class);
getContext().startService(i);
In the manifest, the service is declared like:
<service
android:name=".UnitPullService"
android:exported="false"/>
The point is, that i want to do the whole "download and database filling"-stuff completly independent from the status of the app which is starting the service (so that the user can use other apps while the service is doing its job).
EDIT (Made false assumptions)
The following behaves weird:
Start application
Start service
Close application (swipe away from running-apps-overview)
Start application before service has finished
"service starting"-toast shows up, handleMessage() gets called and DatabaseErros happening (because of unique constrains, but thats not the point).
the other scenario:
Start application
Start service
Close application (swipe away from running-apps-overview)
fillTables() has finished.
It seems that directly after fillTables() has finished and the service gets restarted (Toast shows up).
Q1: So where is my fault, that the running service is going to restart when I start the application while a running service has not finished yet?
Q1.1: How do i call/create a completly independent service, which does not get restarted in such an anoying way, while doing its job?
Swiping away the app puts it in Force-close state. That kills any services attached to it. It won't allow the service or any other activity in the app to run again until the user has launched it.
Now if the user doesn't swipe away, your service will continue to run no matter what app is in the foreground. And if the service is killed by the OS for resources, you can have it automatically restart when they're available. But nothing will make it run services after being swiped away.
I have a service that have an variable life time. It may execute from 5 minutes to 2 hours (for example). So I'm looking for the best approach to do that, and my service must achieve the following features:
Send (to my server) lat-long every 5 seconds and some extra information (string's, boolean's and int's)
I have tried a "normal" service and tried to do something like this to achieve this:
public class MyFiveSecondsService extends Service {
private Handler handler;
Runnable r = new Runnable() {
#Override
public void run() {
//here send my new data
}
};
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(handler == null){
handler = new Handler();
}
handler.post(r);
return super.onStartCommand(intent, flags, startId);
}
}
Actually that code works, but I got some performance problems with that approach, so I tried to do something like this:
public class SendUniquePositionIntentService extends IntentService {
public SendUniquePositionIntentService() {
super("co.bomboapp.Service.IntentService.SendUniquePositionIntentService");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void onHandleIntent(Intent intent) {
//do the logic here
}
}
public class MyFiveSecondsService extends Service {
private Handler handler;
Runnable r = new Runnable() {
#Override
public void run() {
//call my SendUniquePositionIntentService here
}
};
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(handler == null){
handler = new Handler();
}
handler.post(r);
return super.onStartCommand(intent, flags, startId);
}
}
And that approach haven't worked, when I had closed the app any service kept running. So before start any other attempt to achieve this, I want some direction, what's the best approach to do this "infinite loop service" and keep the performance?
I'm using Android 4.1 as min API, and targeting 5.0 API.
My test device is a Nexus 5 running Android 6.
Right now I'm using parse.com as database.
"I have tried a "normal" service...but I got some performance problems"
By default, a service runs on the application's main thread, so when you create a handler with
public int onStartCommand(Intent intent, int flags, int startId) {
if(handler == null){
handler = new Handler();
}
...
}
the handler is associated with the main thread's Looper and all messages and runnables are delivered and later executed on the thread. That's the reason of the "performance problems". From the documentation:
Remember that if you do use a service, it still runs in your application's main thread by default...
Regarding the second approach and the part
"...when I had closed the app any service kept running"
you haven't mentioned how exactly you "close" the app, but what I can see is
public int onStartCommand(Intent intent, int flags, int startId) {
...
return super.onStartCommand(intent, flags, startId);
}
which means that if the system kills the service it, by default, will be recreated. So if "closing" your app means killing it, the following chain of actions takes place:
The system recreates MyFiveSecondsService,
onStartCommand() is called and the handler posts the runnable
within the run() method SendUniquePositionIntentService is started
From the documentation of onStartCommand():
the default implementation calls onStart(Intent, int) and returns either START_STICKY or START_STICKY_COMPATIBILITY.
Note that starting a service from another one (like starting SendUniquePositionIntentService from MyFiveSecondsService in your case) is redundant unless you intended to.
The final part of your question is confusing to me. On one hand it doesn't work for you because "...any service kept running" but, on the other hand, you'd like "do this "infinite loop service""...?
If you only need to send such information as "strings, booleans and ints" to a server (without any feedback to the component that started the service), I suppose it's simply enough for you to use IntentService. This is a "out-of-box" framework that does its work on a background thread (letting you avoid freezing the main thread) and stops itself once it's done. As an example you can use the documentation on IntentService - it's well written.
Also note that the behaviour of a service after killing it by the system depends on the flag returned by onStartCommand(). E.g. use START_NOT_STICKY to not recreate the service after killing the app or START_REDELIVER_INTENT to recreate it with the last Intent redelivered.
What is the recommended approach for checking for new data regardless if the app is in the foreground or background? I am wondering which Android API people are typically using to do this. There seems to be a few ways to achieve my goal, and I want to make sure I'm on the right path.
I have something put together which uses AlarmManager.SetInexactRepeating() to call an IntentService which does the sync and inserts/updates data in the database. This works while the app is in the foreground and background, but if I force stop the app then I keep seeing "Unfortunately, has stopped working" messages when the AlarmManager alarm would've triggered. In this case, I only care about checking for new data only when the app is running in the foreground or background.
My first thought is to detect when the app is force closed, and stop the alarm, but that does not seem possible. So I am asking here, is my approach wrong? If so, which approach is used to perform some periodic task regardless if the phone is in the foreground or background? The problem with the AlarmManager solution I am using is the alarms continue to fire even when the app is closed.
If your idea is to check if your API has new data and perform a background sync to your local database or other data storage, I think you would like to take a look at this:
Creating a Sync Adapter
Running a Sync Adapter
The Sync adapter is the recommended way of achieving this in Android. The pros of using it are multiple:
Optimisations out of the box - the OS bundles calls, uses the most appropriate windows to run the sync adapter at a minimal bandwidth and battery cost
The lifecycle of your background sync component is managed internally by the OS
Observers can be notified when data has been changed so the UI can be updated easily
Multiple ways of running the sync - at intervals, automatically with the OS message to keep TCP/IP connections open or on demand
However, implementing this requires some things, that can cause a bit of a pain at first:
It is mandatory that the adapter works with a ContentProvider
Sync Adapters use Account for authentication. If this is not needed, a Stub has to be provided
For backgrounding on Android usually you use even a Service that can run alone and independently from the App or a Bounded service that takes and returns data from the App. A complete reference on backgrounding can be found here
Using a Service is the right way to go. Have your app start the Service and it will continue running while the app is in the foreground or the background. Then, if you want to kill the Service when your app closes, you could just call stopService(yourServiceIntent); from the onDestroy() override in your app's activity. That should effectively shut down the service when the app closes.
So some sample code of how this works (taken from the Services docs)...
The Service (just Logs a message every 1 second for 60 seconds):
public class MyService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
long endTime = System.currentTimeMillis() + 60*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(1000);
Log.d("SERVICE", "The service is still running.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
}
}
And in your activity you would do something like:
public class MainActivity extends AppCompatActivity {
Intent serviceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
}
#Override
protected void onDestroy() {
stopService(serviceIntent);
super.onDestroy();
}
I am developing android application using rabbit mq pub/sub technology. I want to listen incoming message in android background service. Can I run thread in android background service ?
public class MessagingService extends Service {
private Thread subscribeThread;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
subscribeThread = new Thread(new Runnable() {
#Override
public void run() {
//Connecting to server and listen incoming message.
}
});
subscribeThread.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
subscribeThread.interrupt();
}
}
Yes you can run new thread in Android Service.
Please see note in documentation here: http://developer.android.com/guide/components/services.html
Caution: A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work.
Hope this will help you.