I keep getting the error in the header and I don't know what to do..(this is a water reminder app.) There are a lot of ridiculous topics in the forums. and nobody answered properly. I use this to run when the device restarts. I have examined many issues, but no one answered properly.
Please help me. Thanks in advance!
This is my BootReceiver class
public class BootReceiver extends BroadcastReceiver {
#SuppressLint("UnsafeProtectedBroadcastReceiver")
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, BootService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(service);
Log.d("tag_boot","foreground service start");
} else {
context.startService(service);
Log.d("tag_boot","service start");
}
}
}
and this is my BootService class
public class BootService extends Service {
private String MAIN_DATA = "com.xxxx.xxxx.MAIN";
private SharedPreferences.OnSharedPreferenceChangeListener sharedpreflistener;
public BootService() {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(MAIN_DATA, Context.MODE_PRIVATE);
waterreceiver();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
public void waterreceiver( int su_aralik) {
Calendar thatDay = Calendar.getInstance();
Calendar today = Calendar.getInstance();
int today_month_day = today.get(Calendar.DAY_OF_MONTH);
int today_month = today.get(Calendar.MONTH);
int today_year = today.get(Calendar.YEAR);
thatDay.setTime(new Date(0)); /* reset */
thatDay.set(Calendar.DAY_OF_MONTH, today_month_day);
thatDay.set(Calendar.MONTH, today_month); // 0-11 so 1 less
thatDay.set(Calendar.YEAR, today_year);
thatDay.set(Calendar.HOUR_OF_DAY, 8);
thatDay.set(Calendar.MINUTE, 0);
thatDay.set(Calendar.SECOND, 0);
Calendar calendar = Calendar.getInstance();
if (calendar.get(Calendar.HOUR_OF_DAY) < 23 && calendar.get(Calendar.HOUR_OF_DAY) > 7) {
thatDay.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
} else {
thatDay.set(Calendar.DAY_OF_MONTH, today_month_day + 1);
}
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, WaterAlarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 7, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Objects.requireNonNull(alarmManager).setRepeating(AlarmManager.RTC_WAKEUP, thatDay.getTimeInMillis(), waterlist[water_pos], pendingIntent);
}
}
Manifest
<receiver android:name=".AlarmReceiver" />
<receiver android:name=".WaterAlarm" />
<receiver android:name=".DietAlarm" />
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<service
android:name=".BootService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
startForegroundService itself handles versioning no need to handle from ourselves.
Start service:
Intent service = new Intent(context, BootService.class);
ContextCompat.startForegroundService(this, service)
Stop service:
stopService(new Intent(this, BootService.class));
Related
Test: sdk 19
My manifest
<receiver android:name=".pushnotification.TimeAlarm"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I set up alarm manager
private void setAlarm(String portionName, String orderId, int time, int requestCode) {
Intent intent = new Intent(this, TimeAlarm.class);
intent.putExtra(TimeAlarm.PORTION_NAME, portionName);
intent.putExtra(MainScreenActivity.ORDER_ID, orderId);
intent.putExtra(ALARM_REQUEST_KEY, requestCode);
int id = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, id, intent, FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + time, pendingIntent);
}
This is my receiver
public class TimeAlarm extends BroadcastReceiver {
public static final String PORTION_NAME = "portionName";
private NotificationManager mNotifyMgr;
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = (int) System.currentTimeMillis();
//Do something here
}
}
I have tried a lot of solutions and I can see nothing wrong with my code. But the receiver cannot receive alarm broadcast when the app is closed. When the app is paused, it works ok
You should also register for this intent
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
I am trying to create a service and set an alarm through it. I need to run the service in background to keep the broadcaster reciever running even if the app is closed. I tried using START_STICKY, running service in a separate child process as well as a global process, all in vain. What should I do ?
Alarm.java
package com.simpleapps.simpleweather;
import ...
public class Alarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP,150);
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show();
}
public void setAlarm(Context context)
{
Log.d("Alarm","Started");
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60, pi); // Millisec * Second * Minute
}
public void cancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
HelloService.java
package com.simpleapps.simpleweather;
import ...
public class HelloService extends Service
{
Alarm alarm = new Alarm();
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("Alarm","New Service");
alarm.setAlarm(this);
return START_STICKY;
}
#Override
public void onStart(Intent intent, int startId)
{
alarm.setAlarm(this);
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simpleapps.simpleweather">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".today_details" />
<activity android:name=".forecast_details"/>
<receiver android:process=":remote" android:name=".Alarm" android:exported="true">
</receiver>
<service
android:name=".HelloService"
android:enabled="true">
</service>
</application>
</manifest>
Starting Service -
Intent intent = new Intent(this, HelloService.class);
startService(intent);
Update : It is working on every device except my Lollipop 5.0 device AsusZenfone2
I've tried your code and it's working ok on the emulator. One thing I've notice is that:
* setRepeating
* <b>Note:</b> Beginning in API 19, the trigger time passed to this method
* is treated as inexact: the alarm will not be delivered before this time, but
* may be deferred and delivered some time later. The OS will use
* this policy in order to "batch" alarms together across the entire system,
* minimizing the number of times the device needs to "wake up" and minimizing
* battery use. In general, alarms scheduled in the near future will not
* be deferred as long as alarms scheduled far in the future.
So I've change the Alarm to look like so (It's just illustration, you could do it without static fields):
public class Alarm extends BroadcastReceiver
{
private static boolean sAlarmCanceled = false;
#Override
public void onReceive(Context context, Intent intent)
{
if (sAlarmCanceled)
return;
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP,150);
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_SHORT).show();
scheduleNextAlarm(context);
}
public static void enableAlarm(Context context) {
sAlarmCanceled = false;
scheduleNextAlarm(context);
}
public static void disableAlarm() {
sAlarmCanceled = true;
}
private static void scheduleNextAlarm(Context context)
{
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_ONE_SHOT);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, pi);
}
}
And now it get executed precisely every 10 sec. Service runs normal and I was able to remove Application task and see the alarm anyway.
I'm building an enterprise application that needs to get some information about the employees' rooted phones to do corporate management.
This thread needs to run each five minutes.
I'm using an Activity that is started by a broadcast(BOOT_COMPLETED) when the android boots up, and it starts an infinite thread to send this information to server.
My current problem is my application is being killed by android after the user opens a lot of others apps.
What would be the better way to keep a thread running in background to send this information to server?
Main Application Class
public static void startService(Context mContext){
try{
//Schedule Service.
scheduleService(mContext);
//Call onUpdate.
onUpdate();
}catch (Exception o){
Utilities.log(o.toString());
}
}
public static void scheduleService(Context mContext){
try{
final int NOTIFICATION_INTERVAL = 5 * 60 * 1000;
Intent mIntent = new Intent(mContext, ServiceReceiver.class);
AlarmManager mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
PendingIntent mPendingIntent = PendingIntent.getBroadcast(mContext, 1, mIntent, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), NOTIFICATION_INTERVAL, mPendingIntent);
}catch (Exception o){
Utilities.log(o.toString());
}
}
ServiceReceiver
public class ServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context mContext, Intent intent) {
Utilities.log("Service Received");
//Start Service.
MyApplication.startService(mContext);
}
}
AndroidManifest
<receiver
android:name=".BootUpReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.REBOOT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<receiver android:name=".ServiceReceiver"/>
BootUpReceiver
public class BootUpReceiver extends BroadcastReceiver
{
public void onReceive(Context mContext, Intent mIntent){
Utilities.log("BootUp Received.");
//Start Service.
MyApplication.startService(mContext);
}
}
create a static broadcast receiver for Repeating Alarms and start Intent Service from broadcast don't use infinite Thread
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationStatus.setupNotification(context); // if you restart your phone
}
}
class NotificationStatus{
//Call only one time from app from any activity
public static void setupNotification(Context context) {
final int NOTIFICATION_INTERVAL = 5 * 60 * 1000;
Intent myIntent1 = new Intent(context, NotificationReceiver.class);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 1, myIntent1, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), NOTIFICATION_INTERVAL, pendingIntent1);
}
}
public class NotificationReceiver extends BroadcastReceiver {
private static final int mNotificationId = 0;
#Override
public void onReceive(Context context, Intent intent) {
//start your services here for sending data
Intent intent1 = new Intent(context, SyncService.class);
context.startService(intent1);
}
}
public class SyncService extends IntentService {
public SyncService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
//Write code here for sending data to server
}
}
AndroidManifest
<receiver android:name="NotificationReceiver" />
<receiver android:name="BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
Define Service in Manifest
<service android:name=".SyncService"/>
You need to make your application an Android service.
I have been trying to repeat an action using AlarmManager but, it works fine once and then doesn't repeat again and again after 20 seconds.
public class CheckingService extends Service {
private static final String APP_TAG = "com.test";
#Override
public IBinder onBind(final Intent intent) {
return null;
}
#Override
public int onStartCommand(final Intent intent, final int flags,
final int startId) {
Log.d(APP_TAG, "event received in service: " + new Date().toString());
Toast.makeText(CheckingService.this, "TEST", Toast.LENGTH_SHORT).show();
return Service.START_NOT_STICKY;
}
}
BroadcastReceiver to schedule an Alarm:
public class SchedulerReciever extends BroadcastReceiver {
public SchedulerReciever() {
}
private static final String APP_TAG = "com.test";
private static final int EXEC_INTERVAL = 20 * 10;
#Override
public void onReceive(final Context ctx, final Intent intent) {
Log.d(APP_TAG, "onReceive() called");
AlarmManager alarmManager = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctx, MyBraoadCastReciever.class); // explicit
// intent
PendingIntent intentExecuted = PendingIntent.getBroadcast(ctx, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar now = Calendar.getInstance();
now.add(Calendar.SECOND, 2);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
now.getTimeInMillis(), EXEC_INTERVAL, intentExecuted);
}
}
My broadcast receiver that loads the service:
public class MyBraoadCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent eventService = new Intent(context, CheckingService.class);
context.startService(eventService);
}
}
In the last my AndroidManifest.xml which is using startup
<receiver android:name=".SchedulerReciever" android:process=":my_process">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
<service android:name=".CheckingService" android:process=":my_process" >
</service>
<receiver
android:name=".MyBraoadCastReciever" android:process=":my_process"
android:enabled="true"
android:exported="false" >
</receiver>
Your EXEC_INTERVAL is set to 200ms instead of 20 * 1000 (20s).
Also if you use setRepeating, better to use a relative time AlarmManager.ELAPSED_REALTIME_WAKEUP which is a time since the phone boot, and instead of creating a calendar, you can just call SystemClock.elapsedRealtime() or with an optional offset of 2s SystemClock.elapsedRealtime() + 2000.
So your set repeating should looks like:
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 2000, EXEC_INTERVAL, intentExecuted);
I read several threads about repeat asynchronous tasks in background, I first used this way: https://stackoverflow.com/a/6532298 but for some reasons, it seems that after sometime (several hours), it stopped.
So, now I am using this way, but I don't know if this is a good way to proceed:
BroadcastReceiver
public class RetrieveDataTaskBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences mSharedPreferences = context.getSharedPreferences(MY_PREF, 0);
int delayInMs = mSharedPreferences.getInt("set_delay_refresh", 20)*60*1000;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, RetrieveDataService.class);
PendingIntent pi = PendingIntent.getService(context, 0, i, 0);
am.cancel(pi);
if (delayInMs > 0) {
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + delayInMs,
delayInMs, pi);
}
}
}
My service class:
public class RetrieveDataService extends Service implements OnRefreshInterface {
private Context context;
private PowerManager.WakeLock mWakeLock;
private static final String TAG = "REFRESH_SERVICE";
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void handleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.acquire();
//do the work
callAsynchronousTask();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleIntent(intent);
return START_NOT_STICKY;
}
public void onDestroy() {
super.onDestroy();
mWakeLock.release();
}
#Override
public void onCreate() {
super.onCreate();
context = this;
callAsynchronousTask();
}
public void callAsynchronousTask() {
//My asynchronous task => execute a class that extends AsyncTask
[...]
}
#Override
public void onRefreshInterface(int cb_val1, int cb_val2) {
//Callback when refresh is done
[...]
}
}
androidmanifest.xml:
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<service
android:name="com.example.package.RetrieveDataService"
android:enabled="true"
android:label="Refresh Data">
</service>
<receiver
android:name="com.example.package.RetrieveDataTaskBroadcast"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
I also added a way to launch the service when the app starts:
MainActivity:
#Override
protected void onResume() {
super.onResume();
Thread t = new Thread(){
public void run(){
SharedPreferences mSharedPreferences = getSharedPreferences(PREF, 0);
int delayInMs = mSharedPreferences.getInt("set_delay_refresh", 20)*60*1000;
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(MainBaseActivity.this, RetrieveDataService.class);
PendingIntent pi = PendingIntent.getService(MainBaseActivity.this, 0, i, 0);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + delayInMs,
delayInMs, pi);
}
};
t.start();
}
Thank you for your help and advice.
You dont need a service to launch the repeated task when the device starts. Your task will never run when the device is off.
You can set a repeating alarm using Alarm Manager.
If the trigger time you specify is in the past when the device was off, the alarm triggers immediately when the device turns on.
Check this - https://developer.android.com/training/scheduling/alarms.html