I'm fetching a JSON string from a server and write it to a file. I'm using java.util.Timer to run the task repeatedly every hour.
I want to run it exactly 00:00, 01:00, 02:00... 24:00(yes hourly).
Do I have to use Calendar + AlarmManager?
This is the code:
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import java.util.Timer;
import java.util.TimerTask;
public class LoggerServices extends Service {
LoggerTask loggerTask;
TimerTask timerTask;
Timer timer;
Handler handler;
public LoggerServices() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, "CHANNELID")
.setContentTitle("Example Service")
.setContentText("Population Logger")
.setSmallIcon(R.drawable.ic_mode_edit)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
handler = new Handler();
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
loggerTask = new LoggerTask();
loggerTask.execute();
}
});
}
};
timer.schedule(timerTask, 0, 3600000);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
Log.d("DEBUG", "SERVICE DESTROYED");
if (loggerTask != null) {
loggerTask.cancel(true);
timerTask.cancel();
timer.cancel();
}
super.onDestroy();
}
}
The best option for you would probably be AlarmManager. You don't need to use any Calendar class or anything similar, because AlarmManager is already built for use with time in mind, because it needs to happen at an exact time.
One option is to use an alarm type. By doing this you are using the official time intervals provided by AlarmManager. You could also make your alarm go off every two hours by doing a loop of alarm managers, although that won't be that memory efficient and your android app could crash. Also, avoid using Services when trying to do exact-time works.
Because of the unlimited possibilities, it is impossible to create an implementation, so it would be better for you to decide for yourself.
Take a look at the official documentation: https://developer.android.com/reference/android/app/AlarmManager
Also, look at repeated alarms here if you want to do something related with alarms: https://developer.android.com/training/scheduling/alarms
Related
I wanted my Application to send notification everyday to the user, following this link and doing everything as described. The app doesn't send notifications. The buildLocalNotification function is being triggered every 60 seconds, but no Notification is displayed. I kept an Interval of 2000 ms but android changed it to 60 Seconds.
Logcat Message: Suspiciously short interval 2000 millis; expanding to 60 seconds Every 60 seconds the notification function is triggered.
This is my
NotfBroadcastReceiver.class
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import androidx.core.app.NotificationCompat;
#SuppressWarnings("deprecation")
public class NotfBroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Get notification manager to manage/send notifications
//Intent to invoke app when click on notification.
//In this sample, we want to start/launch this sample app when user clicks on notification
Intent intentToRepeat = new Intent(context, SplashScreen.class);
//set flag to restart/relaunch the app
intentToRepeat.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//Pending intent to handle launch of Activity in intent above
PendingIntent pendingIntent =
PendingIntent.getActivity(context, NotificationHelper.ALARM_TYPE_ELAPSED, intentToRepeat, PendingIntent.FLAG_UPDATE_CURRENT);
//Build notification
Notification repeatedNotification = buildLocalNotification(context, pendingIntent).build();
//Send local notification
NotificationHelper.getNotificationManager(context).notify(NotificationHelper.ALARM_TYPE_ELAPSED, repeatedNotification);
}
public NotificationCompat.Builder buildLocalNotification(Context context, PendingIntent pendingIntent) {
NotificationCompat.Builder builder =
(NotificationCompat.Builder) new NotificationCompat.Builder(context)
.setContentIntent(pendingIntent)
.setSmallIcon(android.R.drawable.arrow_up_float)
.setContentTitle("Workout Reminder")
.setAutoCancel(true);
Log.d("DEBUG", "buildLocalNotification: "+"Notification");
return builder;
}
This is my
AlarmBootReceiver.class
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
//only enabling one type of notifications for demo purposes
NotificationHelper.scheduleRepeatingElapsedNotification(context);
}
}
}
This is the code that turn notification on and off:
swnotf.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b)
{
if(b)
{
Log.d("DEBUG", "onCheckedChanged: "+ "ON");
CommonFunctions.setSwitchState(getContext(),"ON");
NotificationHelper.scheduleRepeatingElapsedNotification(getContext());
NotificationHelper.enableBootReceiver(getContext());
}
else
{
Log.d("DEBUG", "onCheckedChanged: "+"OFF");
CommonFunctions.setSwitchState(getContext(),"OFF");
NotificationHelper.cancelAlarmElapsed();
NotificationHelper.disableBootReceiver(getContext());
}
}
});
Please I have already spent THREE days trying other solutions and fixing this. I don't want to spend more time on this. Any help would be Appreciated.
Thank you.
I am running a telemetry service in my app. This service is checking for changes in WiFi environment once a second and if changes are detected it notifies a remote db. I need this service to continue running even if the app is swiped from recent apps or closed.
I followed Continue Service even if application is cleared from Recent app and it seems to work on many devices except for Xiaomi. I've tried many things advised for this device:
enable auto-start.
disable battery optimization for that app.
Tried using a broadcast receiver to start the service
Tried using timer thread and scheduleExecutorservice instead of runnable. didn't make a difference.
This is my latest sample code :
package com.example.csi1;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
public class MainService extends Service {
public Context context = this;
public Handler handler = null;
public static Runnable runnable = null;
public static int count = 0;
public int restart = 0;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Toast.makeText(this, "MainService onStartCommand", Toast.LENGTH_LONG).show();
Bundle extras = intent.getExtras();
count = 0;
handler = new Handler();
runnable = new Runnable(){
public void run() {
count = count+1;
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo;
wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo.getSupplicantState() == SupplicantState.COMPLETED) {
String ssid = wifiInfo.getSSID();
Log.i("Service", "SSID:"+ssid);
Toast toast = Toast.makeText(context, "Service iter " + String.valueOf(count)+ " " + ssid, Toast.LENGTH_LONG );
toast.setGravity(Gravity.TOP|Gravity.RIGHT, 0, 0);
toast.show();
}
handler.postDelayed(runnable, 1000);
}
};
handler.postDelayed(runnable, 3000);
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Toast.makeText(this, "onTaskRemoved", Toast.LENGTH_LONG).show();
if (restart == 0) {
PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), MainService.class),
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
restart=1;
Toast.makeText(this, "Service restarted", Toast.LENGTH_LONG).show();
}
}
#Override
public void onDestroy(){
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
if (restart == 0) {
PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), MainService.class),
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
restart=1;
Toast.makeText(this, "Service restarted", Toast.LENGTH_LONG).show();
}
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
it runs fine on Samsung device and google nexus emulator, but whenever i run it on Red mi and swipe the app from recent apps,app dies and service with it. Is there a solution for Red mi devices or this is some well known limitation ?
Xiaomi's MIUI and a couple of others are very aggressive on removing background services. As a user you are able to disable it following these steps (for xiaomi). But I am not aware of a solution to circumvent it as a developer.
So you're not doing anything wrong, some phones just don't like background services taking battery life. Similar discussion can be found here: "Protected Apps" setting on Huawei phones, and how to handle it. Their solution is basically having the user disable it by calling the optimization manager for each of the problematic devices
The main thing i just want to do is that i have to check on me webservice when my application is closed when it gets any alert on webservice then it shows notification or activity.
I read about services and make an example but when i remove the application from recent apps then some time the service is restarted or some the service got killed to.
Code:
package com.usamaakmal.startedservice;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
import android.widget.Toast;
public class NewService extends Service {
public NewService() {
}
int i = 0;
Handler handler = new Handler();
Thread runnable = new Thread() {
#Override
public void run() {
i++;
Toast.makeText(getBaseContext(), "Hello World! " + i, Toast.LENGTH_SHORT).show();
handler.postDelayed(this,1000);
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
handler.postDelayed(runnable,2000);
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
Removing app from recent apps list kills app process. Returning START_STICKY from onStartCommand() means you want the system to restart the service after it was killed (either because you removed the app from recents list or system killed service because it ran out of resources).
If you want to keep your service (and it's process) alive you will need foreground service.
System tries to keep foreground services alive as long as possible.
See: Running service in foreground
I am currently trying to set up the date picker and time picker to fire out a notification when the time is reached. I have created a method in MainActivity and this is being called from AlarmReceiver. Every time the timer reaches the set amount, the application is crashing and no errors are being shown in logcat.
I know it is something to do with this method being called from AlarmReceiver, i just don't know what the problems is. This method is also currently linked to a button which is working when pressed (buttonStopAlarm) fires a notification when pressed as wanted) so overall the method does work, it's just not working when being called from another class.
Any help would be greatly appreciated! Thank you!
AlarmReceiver
package servicealarmdemo.test2;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class AlarmReceiver extends BroadcastReceiver {
MainActivity main = new MainActivity();
#Override
public void onReceive(Context arg0, Intent arg1) {
Toast.makeText(arg0, "Alarm received!", Toast.LENGTH_LONG).show();
main.addNotification();
}
}
By doing this MainActivity main = new MainActivity(); you are just creating an instance of MainActivity but it will not have it's context mean this which is basically provided when Activity is started by the OS
so move you Notification code in your Receiver and use arg0 as context
public class AlarmReceiver extends BroadcastReceiver {
//MainActivity main = new MainActivity();
Context cxt;
#Override
public void onReceive(Context arg0, Intent arg1) {
Toast.makeText(arg0, "Alarm received!", Toast.LENGTH_LONG).show();
cxt = arg0;
//main.addNotification();
addNotification();
}
public void addNotification() {
NotificationCompat.Builder builder =
new NotificationCompat.Builder(cxt)
.setSmallIcon(R.drawable.icon_transperent)
.setContentTitle("Achieve Alert!")
.setContentText("This is a reminder for your deadline!");
Intent notificationIntent = new Intent(cxt, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(cxt, 0, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
// Add as notification
NotificationManager manager = (NotificationManager)cxt.getSystemService(Context.NOTIFICATION_SERVICE);
builder.setVibrate(new long[] { 0, 1000, 1000, 1000, 1000 });
manager.notify(0, builder.build());
}
}
I am trying to build a simple app that sends notifications to the device but only on a specific day/time. I have been able to get the notification part to work but cant seem to get the day & time problem solved. Any ideas?
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class NotificationsActivity extends Activity {
int notificationID = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View view) {
displayNotification();
}
protected void displayNotification()
{
Intent i = new Intent(this, NotificationView.class);
i.putExtra("notificationID", notificationID);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, i, 0);
NotificationManager nm = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
Notification notif = new Notification(
R.drawable.ic_launcher,
"Reminder: Meeting starts in 5 minutes",
System.currentTimeMillis());
CharSequence from = "System Alarm";
CharSequence message = "Meeting with customer at 3pm...";
notif.setLatestEventInfo(this, from, message, pendingIntent);
notif.vibrate = new long[] { 100, 250, 100, 500};
nm.notify(notificationID, notif);
}
}
You need to use an AlarmManager to schedule these events. Then, from the callbacks, you show the notifications.
See for example Creating a Notification at a particular time through Alarm Manager
Be careful, as AlarManager will be cleared when the device reboots (you may need to re-register then on boot completed if necessary).
See this link Notification in Android Using AlarmManager, BoradCastReceiver & Services
It may be help you.