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();
}
}
Related
I am using Background service in our application:
public class BackgroundService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.postDelayed(r, 5000);
return START_STICKY;
}
Handler handler = new Handler();
Runnable r = new Runnable() {
#Override
public void run() {
handler.postDelayed(r, 5000);
Log.d("arpit", "connected");
}
};
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent restartServiceIntent = new Intent(Appclass.getInstance().getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(Appclass.getInstance()
.getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent);
}
}
It's working fine, and also works if I close or kill the application.
but on some devices like oppo A33F , Lenovo Vibe K5 etc push notification is not getting through, and also the service class is destroyed after killing the application. I checked in running application section of device but my application is not showing by which means service class is destroyed, after killed the application. How can I resolved this and keep my service continuously running even after the app is killed.
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 would like to know if this is the proper way for stopping my periodically called service or not. I have a static boolean variable isServiceStopped in my MainActivity where I can start or stop the ongoing service by clicking on a button. As you see I reschedule my service in the onDestroy() method with AlarmManager, so if I called stopService() in my MainActvity it would just destroy the service but reschedule it again so there would not be any effect.
This is why I am using a flag, a static boolean variable that I can set in my MainActivity: if I click the button to stop the service I set this flag true and the service will not be rescheduled again as it will not run in the onDestroy() method.
This is working, but I personally believe that this is just a bad workaround since if I close the app how would the system find the static variable if only the service is running? So what is the proper way doing this? Should I put the reschedule part in the onStartCommand()?
Thanks!
public class AsyService extends Service {
#Override
public IBinder onBind(Intent i) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
//Right now I have a static variable defined in MainActivity to set the boolean isServiceStopped
if (!MainActivity.isServiceStopped){
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 15),
PendingIntent.getService(this, 0, new Intent(this, AsyService.class), 0)
);
}
}
}
MainAcvitiy:
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 1, new Intent(MainActivity.this, AsyService.class), PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.cancel(pendingIntent);
}
});
The correct approach would be to recreate the original pending intent, cancel it, and remove the service from the Alarm Manager. I dont know why you would want to terminate the service from within itself.
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(pendingIntent);
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) {}
}
}
I am building an android app and when it is running I need to make a call to the my web server at each minute if the user is connected to a certain network.
I plan to use a service to make that call but how do I call it at each minute?.
I think i need to use alaarm manager but where do I initalize it? in my start activity? I only need to execute the service when my app is running.
Thanks for your help.
If you want to call server only if app is running then no need to use alarm manager. there are other options like
CoundDownTimer
Thread
I prefer CoundownTimer in that scenario and you can use like this
CountDownTimer countDownTimer = new CountDownTimer(1000000, 60 * 1000) {
#Override
public void onTick(long millisUntilFinished) {
// Do something on a tick.
}
#Override
public void onFinish() {
// Do something, maybe?
this.start();
}
};
countDownTimer.start();
Try this ::
You can call this timer in your activity where you want it
private Timer autoUpdate;
#Override
public void onResume() {
super.onResume();
autoUpdate = new Timer();
autoUpdate.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
//call your service from here
}
});
}
}, 0, 60000);//set time interval according to your requirement
}
Feel free to ask if you have any query :)
in Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TestAlarmMessageReceiver almesr = new TestAlarmMessageReceiver(this, time);
}
BroadcastReceiver:
public class TestAlarmMessageReceiver extends BroadcastReceiver {
public TestAlarmMessageReceiver() {
}
public TestAlarmMessageReceiver(Context context, int timeout) { //timeout in seconds
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, TestAlarmMessageReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),
timeout*60*1000, pendingIntent);
}
#Override
public void onReceive(Context arg0, Intent arg1) {
arg0.startService(new Intent(arg0, TestMessageService.class));
}
}
Service:
public class TestMessageService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
messageUpdateTask();
return super.onStartCommand(intent, flags, startId);
}
private void messageUpdateTask(){
GetMessagesUpdateAsyncTak getMessUpd = new GetMessagesUpdateAsyncTak();
getMessUpd.execute(this);
}
}
Call your web server using AsynTask http://developer.android.com/reference/android/os/AsyncTask.html
In onPost method in AsynTask class wait for one minute and call AsynTask.
You can call AsynTask by using below code :
BLSyncingProcedure objSyncingProcedure=new BLSyncingProcedure();
objSyncingProcedure.execute(HomeScreen.this);
BLSyncingProcedure is your AsynTask class name.