App crashes when BroadcastReceiver gets called - android

I have two small questions;
My app's BroadcastReceiver works fine when the app is running, I get the "Tuesday at 2" toast message perfectly and it updates the app, but when I close my app, that means the app stops running, it doesn't get called but instead it crashes "Your app stopped working", so it knows it's supposed to call it, but doesn't, right?
It seems that the BroadcastReceiver gets called everyday at around 2pm, not only on Tuesdays at 2pm, I want the app to update once a week. Is it maybe because I call my setAlarm() method on my UpcomingFragment's onCreate?
In the UpcomingFragment class (where I set the alarm for it to go off each Tuesday at 2)
private void setAlarm(){
AlarmManager alarmMgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), UpdateReceiver.class);
intent.putExtra("greeting", "Hello");
PendingIntent alarmIntent = PendingIntent.getBroadcast(getActivity(), 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
calendar.set(Calendar.HOUR_OF_DAY, 14);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
}
In the BroadcastReceiver's onReceive()
public class UpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
UpcomingFragment.getInstance().update();
//if tuesday
Toast.makeText(context, "Tuesday at 2" , Toast.LENGTH_LONG).show();
}
}
Manifest:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".UpdateReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
i can't provide you with the logcat, cause it doesn't print it when it cashes, i don't know if my android studio is at fault here or my app. Thanks!

You can't manipulate Fragments inside a BroadCastReceiver's context. Essentially broadcast receivers are run inside application context and in which you can't access UI stuff.
If you would like to start an Activity once that broadcast is fired, you would need the following code:
Intent intent = new Intent(context, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Note: Accessing to UI (including Fragments) must be done in an activity context.
Update #1
It seems that the BroadcastReceiver gets called everyday at around 2pm, not only on Tuesdays at 2pm, I want the app to update once a week. Is it maybe because I call my setAlarm() method on my UpcomingFragment's onCreate?
I think I have a better approach than yours.
Getting current time and setting its day of week to Tuesday may result in weird behaviors.
Using a boot completed broadcast receiver to set the alarm may be better.
For the former, your scheduling codes should set the alarm to the nearest coming Tuesday on 2 PM. For this, this answer may be helpful.
For the latter, first, add the following permission to your manifest file.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Then, define another broadcast receiver and declare it to the manifest file.
<receiver android:name="your.package.name.BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
In your newly created broadcast receiver add this code.
#Override
public void onReceive(Context context, Intent intent) {
// Set the alarm to coming Tuesday on 2 PM
}
This ensures your app to get updated on every Tuesday on 2 PM in all circumstances.

Related

AlarmManager is discarded when application is cleared from background

This is how I am creating an alarm.
When the app is still running in background the alarm is fired.
but when it is cleared from the recent apps, the alarm is getting discarded. I am registering a new receiver and providing a unique action for differentiation between two alarms. Is there any mistake in my code.
String filter_action = "myPackageName" + request_code_value +"_time";
IntentFilter filter = new IntentFilter(filter_action);
registerReceiver(new AlarmReciever(), filter);
Intent intent = new Intent(filter_action);
intent.putExtra(getString(R.string.get_current_intent_value), request_code_value);
intent.putExtra(getString(R.string.alarmtext), alarm_title);
intent.putExtra(getString(R.string.alarm_time), newAlarm_Choose_Alarm_Value.getText().toString());
Calendar calNow = Calendar.getInstance();
Calendar calSet = (Calendar) calNow.clone();
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, request_code_value, intent, 0);
calSet.setTimeInMillis(timeInMillis);
if (calSet.compareTo(calNow) <= 0) {
// Today Set time passed, count to tomorrow
calSet.add(Calendar.DATE, 1);
}
alarmManager.set(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(), pendingIntent);
Manifest file.
<receiver android:name="com.bigbangpartners.YoWakeUp.activities.AlarmReciever" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="AlarmManager_Start" />
</intent-filter>
</receiver>
Please help me.
Thanks in advance.
If you are registering and de-registering the BroadcastReceiver programmatically in your Activitys, then a BroadcastReceiver created in this way will remain in existence only as long as the app process is alive. So when you remove your app from the list of recent apps, this BroadcastReceiver is also, in effect, destroyed.
On the other hand, a BroadcastReceiver registered in the manifest is a global, permanent component of an Android app that remains in existence forever, whether the app process is alive or not.
If you want your alarms to be activated even when the app is not in the foreground, then you need to register the BroadcastReceiver in the app manifest and specify the alarm action as well. You are not doing that, and this, I believe, is the root of your problem.
What you should do:
1. Define your BroadcastReceiver in manifest like this:
<receiver android:name="com.bigbangpartners.YoWakeUp.activities.AlarmReciever" >
</receiver>
2. Remove all calls to registerReceiver() and unRegisterReceiver() in your app code as that is not needed.
3. Define your alarm Intent like this:
Intent intent = new Intent(this, AlarmReceiver.class);
Rest of code remains same. First try this and see if it works.

Service or IntentService or AlarmManager approach

I am building a game-like application and I've been reading about all the different approaches of running things with Services in background, foreground, Alarms and so on, and I am a bit confused.
My app would go like this (example):
user presses a button in Main, then he can close the app
after 30 minutes Activity1 opens up
user finishes whatever he needs to do in that activity, which
triggers the next activity to start after 2 hours
after 2 hours Activity2 opens up
user finishes whatever he needs to do there as well, triggering the
next one
after a day Activity3 opens up, and so on
What would be the best approach? Have a service running continuously to open those activities, or get a new alarm set up to start every time the user finishes one of the activities?
Please do not create a service just to it can stay idle for several hours. It makes no sense.
What you need to do is to create an alarm. something like:
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
This is just a general example for the Alarm API. You will need to adjust it for your needs.
Finally - please be aware: alarms is not boot resilient! That is: if for any reason
the user's device goes down, all of your alarms will be lost.
if you do want your app to be boot resilient you will need to register to an
event called RECEIVE_BOOT_COMPLETED (think post-boot) where you will restart your pending
alarms:
//manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name=".MyBootReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
//java class
public class MyBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
// restart alarms
}
}
}
Hope it helps

Alarm doesn't trigger after reboot

I have an alarm to reset a data connection say every 15 minutes. The problem is, once the phone is rebooted, the application gets killed and the alarm (service) doesn't trigger anymore.
(This is not a duplicate, the other similar questions on SO do not solve my problem.)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name="com.sang.mobiledata.ResetBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Broadcast Receiver:
public void onReceive(Context context, Intent intent) {
// if(CONN_ACTION.equals(intent.getAction())) {
if (intent.getAction().equalsIgnoreCase(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE")) {
MainActivity objMain = new MainActivity();
objNetwork.setMobileDataEnabled(context, false);
objNetwork.setMobileDataEnabled(context, true);
}
if (intent.getAction().equalsIgnoreCase(
"android.intent.action.BOOT_COMPLETED")) {
// code to restart/resume/retain alarm
Code to fire alarm (on the onClick):
Intent myIntent = new Intent(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE");
myIntent.putExtra("FLAG_KEY", false);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
long interval = intHrs * 3600000 + intMins * 60000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), interval, pi);
long mins = interval / 60000;
Toast.makeText(
MainActivity.this,
"Data Connection will be reset every " + mins
+ " minute(s).", Toast.LENGTH_SHORT).show();
}
Any suggestions please?
Read the AlarmManager document, there it is written, that AlarmManager will not hold alarms after reboot.
As per the Android Developers,
.... Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
And regarding BOOT_COMPLETED, they write:
... This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.
As for permission is concerned, you have already registered that. Well what probably happening is, the service BOOT_COMPLETED is being used locally, with the application. The reboot of the mobile is system activity, which is not overridden to accomplish re-registry of the alarms being saved. But I am not sure. So, you need to do something when execution comes in hand of BOOT_COMPLETED.
Read Automatically starting Services in Android after booting, this might help you with it.
What I did was, I registered all the alarms and formed a database, using SQLite; On restart, I use to reset all the alarms. Well that worked for me. If you want to go with my process then,
Make a database for your alarms, and save them there. Write your application in such a way that, when the phone restarts, the AlarmManager resets all the alarms. This is how it works.
In Automatically starting Services in Android After booting again. It is written:
Also note that as of Android 3.0 the user needs to have started the application at least once before your application can receive android.intent.action.BOOT_COMPLETED events.

Starting a service on BOOTUP and then scheduling the service to run every 10 minutes?

I would like to have a service run on bootup and then scheduled to run every 10 minutes. How can I go about this?
If on boot-up can I force a schedule for 10 minutes, but I presume I would need to schedule this every time on boot-up because after a reboot all schedules are lost?
There's a nice little tutorial here that explains how to start a service at boot time that just keeps running and at some regular interval does something (writes to a log file, in the case of the tutorial).
As #CommonsWare points out, this creates an unnecessary load on the system. A better approach is to schedule a repeating alarm with AlarmManager, as described in this thread. You can register your app to receive the BOOT_COMPLETED broadcast (as described in the above tutorial) and in response schedule the alarm.
in my application I've registered a broadcast receiver on the ACTION_BOOT_COMPLETED Intent to be notified when the device boot has been completed.
To achieve the result you have to specify in your manifest file the following:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver
android:name=".YOUR_BROADCAST_RECEIVER">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
In the BroadcastReceiver I started the service with
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, serviceClass));
...
}
Finally in the onStartCommand of the service
public int onStartCommand(Intent intent, int flags, int startId) {
...
setNextSchedule();
...
}
private void setNextSchedule() {
long time = WHEN_YOU WANT_THE SERVICE TO BE SCHEDULED AGAIN;
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(this, 0,new Intent(this, this.getClass()), PendingIntent.FLAG_ONE_SHOT);
am.set(AlarmManager.RTC_WAKEUP, time, pi);
}
The AlarmManger will use the pending intent to send to your service the intent you passed. Have a look here
bye

How to save scheduled alarm after app was killed by Android or task killer?

Code that schedules alarm.
PendingIntent sender = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, time, sender);
Its working fine, but when I kill my app in task killer, I lost my scheduleed alarm. How to solve this problem?
have your application broadcast a message as its being killed, and when this message is broadcast, then have a listener check if the service is still running.. if its not run it. This will insure that your service is running even if the application is killed.
Update
I'll try to create a flow diagram for you
The onDestroy() method is part of a service.
I hope this helps.
UPDATE 2
One thing I forgot to mention is the fact that you ideally only want one instance of the service to be run. So just looking at the ID that is present within the onStart() should be == to 1 to start it else.. ignore it.
Methods of notice of the Service Class:
onStart() : This method is called when the service is being started
onDestroy() : This is the method that is called when a service is being killed
Methods of notice of the BroadcastReciever class:
onReceive(): This methods receives all intents that are sent to it (unless filtered)
Look up examples on BroadcastRecievers (Message Broadcasting) and Service (Starting a service)
References:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
http://developer.android.com/reference/android/app/Service.html
Alarm set by alarm manager is not killed when app is closed, how ever when a reboot occurs all alarms are cleared by the os since there is no persistence. So you need to do the persistence.
Every Time while setting a alarm save the alarm time.
Register a receiver for boot completion.
Set the alarm again on reboot.
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//re register the alarm
}
}
Manifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
.......
<receiver
android:name="BootReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
You could use SharedPreference to save the time (time at when the alarm should be triggered or time at when it should be triggered next)
Use that to set a new alarm at the boot receiver.

Categories

Resources