I've an app that runs in the background, using a service. The main class start the service and when the user stop the main service the background service call to onDestroy function and start over the service on the background. I got a problem when I stay out of the app (on the home page of the phone) the app crash and I don't know why. The app crash on this part of the code startService(new Intent(this, LocationServices.class)); on the Service class. with the error
java.lang.RuntimeException: Unable to stop service LocationServices#1e605b2: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=o/.LocationServices }: app is in background uid
Main Class -
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, LocationServices.class));
}
}
Service Class -
public class LocationServices extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("LocationServices", "Service Start");
return Service.START_STICKY_COMPATIBILITY;
}
#Override
public void onDestroy() {
//super.onDestroy();
startService(new Intent(this, LocationServices.class));
Log.d("LocationServices", "Service End");
}
}
Why is this happening and how can I fix it?
Related
I have my application running a service for shake detect, however in my MainActivity, I have button for log out user, in which I must log out and terminate the service that detects the shake event.
my method for log out in my MainActivity is:
public void signOutAndFinish(){
//Stop Shakeservice
Intent intent = new Intent(this, ShakeService.class);
stopService(intent);
//Go to login activity
Intent iLoginView = new Intent(this, LoginActivity.class);
startActivity(iLoginView);
}
however if I shake my device after logging out, the service recognizes the shake, it is as if it will not kill it immediately:
Intent intent = new Intent(this, ShakeService.class);
stopService(intent);
The code in the method onDestroy is:
#Override
public void onDestroy() {
super.onDestroy();
}
How can I terminate the service so that when I log out the service dies?
Thanks for your help!
You can send a broadcast back your activity in the onDestroy() method of your service and then do the logout.
Here is some sample code of the above idea:
This for your service:
#Override
public void onDestroy() {
super.onDestroy();
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("data","Notice for logout!");
sendBroadcast(intent);
}
And this is for your activity:
private BroadcastReceiver br = new MyBroadcastReceiver();
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter("com.example.broadcast.MY_NOTIFICATION");
registerReceiver(br, filter);
}
#Override
public void onDestroy() {
unregisterReceiver(br);
}
// An inner class at your activity
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
#Override
public void onReceive(Context context, Intent intent) {
YourActivity.this.finish();
// or do anything you require to finish the logout...
}
}
however if I shake my device after logging out, the service recognizes the shake
Then presumably you did not clean up your Sensor stuff in the service's onDestroy() method.
How can I terminate the service so that when I log out the service dies?
You are doing that now. However, if you set up something in the service, such as listening to events from SensorManager, you need to clean that up, typically in onDestroy() of the service.
I am developing android application, so I am starting a service with alarm:
public void scheduleLocationCheckerAlarm() {
Intent intent = new Intent(getApplicationContext(), LocationCheckerReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(this, LocationCheckerReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long firstMillis = System.currentTimeMillis();
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis, 600000, pIntent);
}
LocationCheckerReceiver:
public class LocationCheckerReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LocationNotificator.class);
context.startService(i);
}
Service:
public class LocationNotificator extends Service {
public LocationNotificator() {
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Location checker", "Service running");
//My code is here
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("Location checker", "Service destroyed");
}
So I want this service to be checking for something every 1 minute and to be running all the time, even when the application is closed by the user.
You must call startForeground(FOREGROUND_ID, buildForegroundNotification(filename)); in order to ensure that your service running continuously. Also, this will post a notification from your app to show the user about the service state. Please follow the reference.
Here is the code :
public class LocationNotificator extends Service {
private static int FOREGROUND_ID=1338;
public LocationNotificator() {
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Location checker", "Service running");
//My code is here
startForeground(FOREGROUND_ID,
buildForegroundNotification(filename));
stopForeground(true);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("Location checker", "Service destroyed");
}
private Notification buildForegroundNotification(String filename) {
NotificationCompat.Builder b=new NotificationCompat.Builder(this);
b.setOngoing(true);
b.setContentTitle("Some Title")
.setContentText("some File name")
.setSmallIcon(android.R.drawable.stat_sys_download)
.setTicker("downloading");
return(b.build());
}
You need to read this first. https://developer.android.com/guide/components/services.html
In a nutshell, start your service as a foreground service so there's lesser chance of Android killing your service. As a foreground service, you need to display an on-going notification in the status bar.
There's no direct way of making sure your service is never killed by the Android system. A workaround is to send a broadcast in onDestroy() of your service, and have a Receiver in your Android application start the service upon receiving the broadcast.
By the way, it seems that your service is sending location updates periodically to your backend server. This might be better implemented using Firebase Job Dispatcher library or Evernote's Android-Job library.
The service works normally when is started from the MainActivity however when the application is removed from the recent apps or when activity is closed, the service is restarted instead of continuing from where it left off.
public class ServiceExample extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO: Implement this method
return null;
}
#Override
public void onCreate() {
// TODO: Implement this method
super.onCreate();
//Do Something
}
I need to perform an action in the background but it can not be stopped or restarted when the activity ends. The Service Statement is the best to Use?
Try putting this inside your service class.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
Add below code to service and override onStartCommand and return START_STICKY
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceTask = new Intent(getApplicationContext(),this.getClass());
restartServiceTask.setPackage(getPackageName());
PendingIntent restartPendingIntent = PendingIntent.getService(getApplicationContext(), 1,restartServiceTask, PendingIntent.FLAG_ONE_SHOT);
AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
myAlarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartPendingIntent
);
super.onTaskRemoved(rootIntent);
}
I start a service from activity button click that fire a service class and start Broadcastreceiver and it's run in background but I want to unregisterReceiver with a button click from same activity class.it seem not working.I added receiver class to menifest.
Here is my code.
Activity button click for registerreceiver
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent svc = new Intent(this, DemoService.class);
startService(svc);
});
DemoService.class
public class DemoService extends Service {
static final String LOGGING_TAG = "MyDemo";
private static Alarm1 tickReceiver =new Alarm1();
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startId){
super.onStart(intent, startId);
Log.v(LOGGING_TAG, "DemoService.onStart()");
}
#Override
public void onCreate(){
super.onCreate();
Log.d(LOGGING_TAG, "DemoService.onCreate()");
registerReceiver(
new Alarm1(),
new IntentFilter(Intent.ACTION_TIME_TICK));
}
}
Activity button click for unregisterReceiver
unreg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DemoService demo=new DemoService();
demo.unreg();
});
And receiver class
public class Alarm1 extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("tag","working");
}
How can I unregisterReceiver from unreg button click.
If I click in unreg button it show me error java.lang.IllegalArgumentException: Receiver not registered:
create a method for unregistering Receiver in Service class. And call the service with action like.
Intent svc = new Intent(this, DemoService.class);
svc.setAction("com.package.UN_REGISTER");
startService(svc);
and in Service class handle them in onStartCommand ()
like
if(intent.getAction().equals("com.package.UN_REGISTER")
//call your unregister method
Add action in Manifest in your service Tag
<IntentFilter>
<action name = "com.package.UN_REGISTER">
</IntentFilter>
You should use Bound Services for this. Check link for implementation and usage
If you want to correctly register and unregister a BroadcastReceiver. The BroadcastReceiver passed in registerReceiver() and unregisterReceiver() must be the same instance, so is the Context instance be invoked. Because the implement uses Context and BroadcastReceiver instances to uniquely map to a "Register operation".
i need a service in my app that starts first time and runs forever, even if user restart his phone, my service starts automatically without running my app. i write this code but when user restart his phone, my service doesn't start again!!
public class notifService extends Service {
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStart(intent, startId);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
and in the main activity i start service like this:
// start service
Intent service = new Intent(MainActivity.this, notifService.class);
MainActivity.this.startService(service);
thanks for you help.
Listen for android.intent.action.BOOT_COMPLETED in BroadcastReceiver and start your service.
For example
public class YourDefinedBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, notifService.class);
context.startService(service);
}
}
Also, you must hold the permission:
RECEIVE_BOOT_COMPLETED
Ref: Automatically starting Services in Android after booting and Android Start Service on Boot Automatically