I want to close the service when user removes the app from current running app list. Here, what I'm doing, when user starts the app, service gets started and remain in progress. But when user removes the app via swipe, new service is being created. I want to close the service. Below is my code.
// Start service using AlarmManager
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 10);
Intent intent = new Intent(this, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
5000, pintent);
startService(new Intent(getBaseContext(), MyService.class));
MyService.java
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class MyService extends Service {
int count = 0;
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
Toast.makeText(this, "The new Service was Created", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startId) {
// For time consuming an long tasks you can launch a new thread here...
count++;
Toast.makeText(this, " Service Started" + " " + count, Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
}
According with google's employee Dianne Hackborn explains in a comment on one of her Google+ posts, you have to implemente the onTaskremoved on your service.
[W]hat specifically happens when you swipe away a recent task is it:
(1) kills any background or empty processes of the application (see
http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html#Lifecycle
for what this means), and (2) uses the new
http://developer.android.com/reference/android/app/Service.html#onTaskRemoved(android.content.Intent)
API to tell any services of the application about the task being
removed so it can do whatever it thinks is appropriate.
So I think you can do it this way: In that callback you have to stop the service, and tell the alarm manager to stop starting it again. For that, first of all, you need to pass to the service the pending intent that you use with the AlarmManger, so the service can use the intent to cancel the schedule.
At least, you need all this:
In your service
public class MyService extends Service {
private DefaultBinder mBinder;
private AlarmManager alarmManager ;
private PendingIntent alarmIntent;
private void setAlarmIntent(PendingIntent alarmIntent){
this.alarmIntent=alarmIntent;
}
public void onCreate() {
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mBinder = new DefaultBinder(this);
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void onTaskRemoved (Intent rootIntent){
alarmManager.cancel(alarmIntent);
this.stopSelf();
}
}
Then in other file, you create DefaultBinder Class
public class DefaultBinder extends Binder {
MyService s;
public DefaultBinder( MyService s) {
this.s = s;
}
public MyService getService() {
return s;
}
}
in your activity
MyService service;
protected ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
service = ((DefaultBinder) binder).getService();
service.setAlarmIntent(pIntent);
}
public void onServiceDisconnected(ComponentName className) {
service = null;
}
};
protected void onResume() {
super.onResume();
bindService(new Intent(this, MainService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (mConnection != null) {
try {
unbindService(mConnection);
} catch (Exception e) {}
}
}
Related
My app use a background music service.
I have a button to quit my app but I can't find anything to close my app and my service.
I bind my service to my activity.
I tried:
unbindService(serviceConnection);
myService().stopSelf();
stopService(new Intent(this, MediaPlayer.class));
and absolutely nothing works !!! The service continues.
How can I do to destroy my service and how can I do to close my app ??
Tx
EDIT:
I use this in the onCreate method
Intent intent = new Intent(this, serviceClass);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
And in the MediaPlayer class
public class LocalBinder extends Binder {
public MediaPlayer getService() {
return MediaPlayer.this;
}
}
public IBinder onBind(Intent intent) {
Log.i(TAG, "service bound");
init();
return mBinder;
}
And that...
But I dont know if I really need to start the service. Bind the service already starts it
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Now I did this
#Override
public void onDestroy() {
player.stop();
super.onDestroy();
}
The onDestroy method works only if i unbind the service !
This doesnt work at all:
getService().stopSelf();
this.stopService(new Intent(this, MediaPlayer.class));
So, how can I stop the service and how can I close the app ?
This is what I do in my app. onDestroy() method from the activity will be called when you close your app.
private ServiceConnection musicServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
musicService.setCallbacks(MainActivity.this);
musicServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MusicService service disconnected (unbinded)");
musicServiceBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
Intent intent1 = new Intent(this, MusicService.class);
bindService(intent1, musicServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onDestroy() {
super.onDestroy()
if(musicServiceBound){
musicService.stopSelf();
unbindService(musicServiceConnection);
}
}
You wrote myService(), where you are creating another service using ().
For closing your app programmatically you can refer to this question.
I have a service that gives a notification if user has changed his location. I want this service to keep on running until user explicitly force stops my application in application manager. I have used following method:
Intent intent1 = new Intent(context, LocationService2.class);
PendingIntent contentIntent = PendingIntent.getService(context, 0, intent1, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),2*60000, contentIntent);
Service class:
public class LocationService2 extends Service implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("TAG", "STARTLS");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Location services connected.");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
// Use this location to give notification if required.
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}
}
This method does not work on all phones.
Is AlarmManager the best way to do this. If yes, then how can I improve this code to work on all phones?
You should make your service a Foreground Service. You can find a tutorial here.
Manifest Entry
<receiver android:name="YourPackagename.RestartReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="YourPackagename.AlarmReceiver" >
</receiver>
On phone reboot need to reinitialize alarm manager
RestartReceiver.java
public class RestartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intentReciever = new Intent(context, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intentReciever, 0);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + GlobalContext.PUSH_NOTIFICATION_INTERVAL),
GlobalContext.PUSH_NOTIFICATION_INTERVAL, alarmIntent);
}
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//you can put your logic over here
}
}
Put below code in your Splash Screen
private void initService() {
if(!app_preferences.getBoolean("isServiceRunning", false))
{
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intentReciever = new Intent(LoadingScreen.this, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(LoadingScreen.this, 0, intentReciever, 0);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis()+GlobalContext.PUSH_NOTIFICATION_INTERVAL),
GlobalContext.PUSH_NOTIFICATION_INTERVAL, alarmIntent);
app_preferences.edit().putBoolean("isServiceRunning", true).commit();
}
}
//Note: its not good way to check your Alerm service using shared preference is running or not.
The steps to make a never ending service are :
1.) Start service using alarmManager.
2.) Check in onResume if service is running & restart if not.
3.) Return START_STICKY from onStartCommand().
4.) In OnStartCommand() , create a thread and do the needful from that thread .All the logical stuff should be there in while(true).
This way your service will never be killed .
In given code i have put some good things like you can communicate with activity using binder service via listner. You can notify your activity that you lost internet connction by writing code in service...
Create service as sticky which will never end. if user will kill app it will again automatically restart.
When compare to alarm manager you may face duplication/multiple service get started. like we need to identify and prevent that if Alarm manager already i have created then don't start again as per my another answer written in same question.
Manifest.xml
<receiver android:name=".BootCompleteReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver>
<service android:name=".MyService" android:enabled="true" android:exported="false"/>
MyService.java
public class MyService extends Service {
CommunicationListner listener;
public class LocalBinder extends Binder {
public MyService getService() {
// Return this instance of LocalService so clients can call public methods
return MyService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
unregisterReceiver(internetConnectionReceiver);
} catch (Exception e) {
}
registerReceiver(internetConnectionReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
//communication with activity
public void registerChatReceivedListener(CommunicationListner listener) {
this.listener = listener;
}
public void removeChatReceivedListener() {
chatListener = null;
}
private BroadcastReceiver internetConnectionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
public MyService() {
}
}
To restart your service on restart phone
BootCompleteReceiver.Java
public class BootCompleteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
context.startService(new Intent(context, MyService.class));
}
}
}
Put code in you splash screen to start myservice if its already started then also no need to worry.
startService(new Intent(getApplicationContext(), MyService.class));
Start the service anytime it got killed.
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
startService(new Intent(this, LocationService2.class));
}
The solutions in android 5 and higher is using AlarmManger and Broadcast Receiver
I want to create an alarm application, which will sound the alarm when you set the time. I've got it to work partially. I'm stuck at the alarm not being set after the app is closed via recent tray(Not with force stop). To tackle this, I created a service which will run in the background(even if the app is closed) and will sound the alarm.
My problem right now, is that even after using a service, I'm unable to sound the alarm after the app is closed. However, the service seems to be running after the closure of the app(I've seen in running apps. It says My App has a service running in the background).
NOTE : I've also bound the service with my activity so that I can use its methods.
NOTE 2 : The service sounds the alarm when the application is open, Only fails to do so when the app is closed.
This is my code :
Calling the service from my Activity :
public void startOnClick(View view) {
int aHour = alarmTimePicker.getCurrentHour();
int aMin = alarmTimePicker.getCurrentMinute();
Alarms alarm = new Alarms(aHour, aMin); //I've created an Alarms class Seperately
myService.setAlarm2(alarm); //Setting the alarm via service
Toast.makeText(this, "Alarm SET.", Toast.LENGTH_LONG).show();
}
In MyService : `package com.wars.tap.tapwars;
public class MyService extends Service {
private final IBinder myBinder = new MyBinder();
Alarms alarm = new Alarms();
private PendingIntent pendingIntent;
private AlarmManager alarmManager;
private ServiceCallBacks serviceCallbacks;
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
return myBinder;
}
public class MyBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public void setCallbacks(ServiceCallBacks callbacks) {
serviceCallbacks = callbacks;
}
public void setAlarm2(final Alarms alarm){
Runnable r = new Runnable() {
#Override
public void run() {
try {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, alarm.get_hour());
calendar.set(Calendar.MINUTE, alarm.get_min());
AlarmManager AM = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(MyService.this, AlarmReceiver.class);
i.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
pendingIntent = PendingIntent.getBroadcast(MyService.this, 934, i, PendingIntent.FLAG_UPDATE_CURRENT);
AM.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} catch (Exception e) {
}
}
};
Thread t = new Thread(r);
t.start();
}
}
`
So, the setAlarm2 is the method I'm using in the service to sound the alarm. It's working when the app is open, but fails to work when the app is being closed. As you can see, this is my first post on StackOverflow and I'm also new to android programming. I've been stuck with this for a long time and would appreciate some help. Thank you.
Your alarm could be working, but the notification center is not aware of allowing your app any privileges to highlight the event that is occurring. Check out this link here for details on Notifications.
EDIT
Check out the code below I extracted from a previous project. I left out the necessary parts:
public class MyClass extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void onTaskRemoved(Intent rootIntent) {
// Input your code here prior to exit.
stopSelf();
}
}
I have a Bound service which collects locations for 3 minutes every 15 minutes. I start a CountDownTimer once the Service is connected in onServiceConnected of ServiceConnection.
I receive all the Timer callbacks (onFinish) (onTick) perfectly as far the Activity which bindService is visible.
When Device is locked I do not receive any updates from the timer.
MyLocationService
public class MyLocationService extends Service implements MyTimerListener{
private IBinder mBinder = new MyLocationBinder();
public void onCreate() {
locationManager = new MyLocationManager(this);
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyLocationBinder extends Binder
{
public MyLocationService getService()
{
return MyLocationService.this;
}
}
public void startFetchingLocations()
{
if(locationManager != null){
locationManager.startFetchingLocations();
if(publishPeriodCountDownTimer != null) {
publishPeriodCountDownTimer.cancel();
publishPeriodCountDownTimer = null;
}
publishPeriodCountDownTimer = new MyCountTimer(gpsPublishPeriod * 60 * 1000, 1000, MyLocationService.this);
publishPeriodCountDownTimer.start();
}
}
#Override
public void onTimeFinished() {
//Start fetching locations
locationManager.startFetchingLocations(); //Start 3 min CountdownTimer
}
#Override
public void onTick() {
}
public void onAllLocationsRecieved(ArrayList<Location> locations)
{
//Do stuff on Locations
locationManager.stopFetchingGPS(); //Stops 3 min countdownTimer
}
}
MyActivty
public class MyActivity
{
#Override
protected void onStart() {
super.onStart();
btnStop.setVisibility(View.VISIBLE);
MyNoificationManager.cancelAllNotifications();
if (!isLocationServiceBound) {
Intent locServiceIntent = new Intent(this, MyLocationService.class);
bindService(locServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
}
}
private ServiceConnection locationServiceConnection = new ServiceConnection(){
#Override
public void onServiceDisconnected(ComponentName name) {
isLocationServiceBound = false;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyLocationBinder locationBinder = (MyLocationBinder) service;
locationService = locationBinder.getService();
isLocationServiceBound = true;
locationService.startFetchingLocations();
}
};
}
It works as expected when the Activity is visible. The timer doesn't provide any onTick() or onTimeFinished() callbacks when the device is locked.
What could be the problem here ?
The CountDownTimer will not work when the phone goes to sleep mode. This is by design and it's to save battery life.
Alternately you can use android.app.AlarmManager instead to achieve your goal. Following is the sample code how to do that. Set the alaram like below
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyLocationService.class);
intent.putExtra("need_to_fetch_loc", true);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, gpsPublishPeriod * 60 * 1000, alarmIntent);
Add the following method to your MyLocationService class
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(locationManager!= null && intent.getBooleanExtra("need_to_fetch_loc", false))
{
locationManager.startFetchingLocations();
}
return super.onStartCommand(intent, flags, startId);
}
I need to start a service and end it under some condition. I previously used IntentService which I found to be incorrect for the purpose(if I am right). I have started using service with BroadcastReciever. But still can't get the desired result. I may elaborate or even paste my code if needed. But for now, I just need something like a flow chart or pseudocode.
The condition would be checked from Preference settings. If checked, I would like to run the service in background else stop the service. Please, can any one out here help me.
EDITED:
My MainActivity:
public class MainActivity extends ListActivity {
private LocalWorldService s;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
Intent intent = new Intent(this, LocalWorldService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onPause() {
super.onPause();
unbindService(mConnection);
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
LocalWorldService.MyBinder b = (LocalWorldService.MyBinder) binder;
s = b.getService();
Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT)
.show();
}
public void onServiceDisconnected(ComponentName className) {
s = null;
Toast.makeText(MainActivity.this, "Disconnected", Toast.LENGTH_SHORT)
.show();
}
};
My Service:
public class LocalWorldService extends Service {
private final IBinder mBinder = new MyBinder();
private ArrayList<String> list = new ArrayList<String>();
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Magnet is on", Toast.LENGTH_LONG).show();
return Service.START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mBinder;
}
public class MyBinder extends Binder{
LocalWorldService getService(){
return LocalWorldService.this;
}
}
public List<String> getWordList(){
return list;
}
Following are two class for BroadCastReceiver:
public class MyScheduleReceiver extends BroadcastReceiver{
private static final long REPEAT_TIME = 15 * 1000;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyStartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast( context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 15);
service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), REPEAT_TIME, pending);
}
And:
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Intent service = new Intent(context, LocalWorldService.class);
SharedPreferences pref = PreferenceManager
.getDefaultSharedPreferences(context);
Map<String, ?> x = pref.getAll();
boolean momoMagnetIsOn = (Boolean) x.get("key_momo_magnet");
if (momoMagnetIsOn){
context.startService(service);
}
else{
context.stopService(service);
}
}
CORRECTION:
I need to override onDestroy().
override onDestroy method in Service
When ever you want to start a service all you need is
startService(new Intent(this, MainService.class));
And to Stop a service anytime just call
stopService(new Intent(this, MainService.class));
Remember service needs to be declared in AndroidManifest.xml. As you said that your service is working. I'm sure you have done that. Still AndroidManifest.xml
<service android:enabled="true" android:name=".MainService" />