Change Variable in BroadcastReceiver - java

I want to change a variable of a BroadcastReceiver. Unfortunately the App crashed everytime I try to access it.
Here is an example:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.buttonAlarm).setOnClickListener(new View.OnClickListener() {
setAlarm();
});
}
public void setAlarm(){
Calendar calendar = Calendar.getInstance();
calendar.set(datePicker.getYear(),datePicker.getMonth(),datePicker.getDayOfMonth(),timePicker.getCurrentHour(),timePicker.getCurrentMinute(), 0);
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, MyAlarm.class);
pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), Interval*60000, pi);
}
}
This is the MyAlarm.java Class that extends the BroadcastReceiver:
public class MyAlarm extends BroadcastReceiver {
int RecordTimeMinutes;
public void onReceive(final Context context, Intent intent) {
new Handler().postDelayed(new Runnable() {
#Override
public void run(){
//do some stuff
}
}, RecordTimeMinutes * 60000);
}
}
So basically I want to acces the Variable RecordTimeMinutes of the MyAlarm class within the MainActivity class. Is that possible?

For your use-case, why don't you save the value of RecordTimeMinutes into a sharedpreference key?
That way you will be able to access it from both the Activity and the Receiver without any issues.
Directly accessing the variable in the activity might not be possible unless you make it static, which is something you should not do!

Pass the variable from the Activity via the Intent extras:
public void setAlarm(){
Calendar calendar = Calendar.getInstance();
calendar.set(datePicker.getYear(),datePicker.getMonth(),datePicker.getDayOfMonth(),timePicker.getCurrentHour(),timePicker.getCurrentMinute(), 0);
am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, MyAlarm.class);
i.putInt("Interval", 42); // Pass "interval" value here
pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), Interval*60000, pi);
}
And then in the receiver:
public class MyAlarm extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent) {
int interval = intent.getIntExtra("Interval", 0) // Get "interval" value here
new Handler().postDelayed(new Runnable() {
#Override
public void run(){
//do some stuff
}
}, interval * 60000); // Use "interval" here
}
}
That said - you should not be posting a handler to fire in the future inside a BroadcastReceiver. There is no guarantee that your process will still be alive 1 minute from now to execute your code. Instead you could schedule another alarm or use WorkManager to schedule a job to run later.
Hope that helps!

Related

Calling method of different activity via interface leads to error: system service not available before onCreate

I have an AlarmManager in Activity 'PopShowAlarms'. This is a List of alarms, which the user can activate and deactivate. If he does so, the AlarmManager creates a new Alarm. Obviously the user also needs to be able to add alarms. He can do this in the second activity 'PopAddAlarm'. To make this newly created alarm, 'PopAddAlarm' calls a method of 'PopShowAlarms'. There the new data should be converted into an alarm instantly. This always leads to the error, that I can't use SystemServices before onCreate.
First I tried to call the method simply by making a new object of the class
Class class = new Class();
class.method();
This resulted in the error: can't call SystemServieces before onCreate
Now I've been told, that I have to use an Interface to do so, but I still get the same error. Because I'm new to interfaces, I think that's where the mistake might be.
Here is my code:
Activity 'PopShowAlarms':
public class PopShowAlarms extends AppCompatActivity implements interfaceForwardAlarm {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pop_show_alarms);
...
}
#Override
public void onSwitchChange(int position, boolean switchOnOff) {
// when user activates the alarm, this code is triggered
if (switchOnOff) {
RecyclerViewElement currentElement = savedList.get(position);
String time = currentElement.getmAlarmTime();
// deleted methods that convert String 'time' to a calendar object
setAlarm(Calendar);
}
}
});
...
public void setAlarm(Calendar calendar){
AlarmManager alarmManager = (AlarmManager) getBaseContext().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
int count = getCount();
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, count, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
...
// this is the implemented method from the interface
#Override
public void forwardAlarm(Context context, String alarmTime, String activeDays, String motivation, String music) {
setCalendar(alarmTime);
}
}
Second Activity: 'PopUpAdd
public class PopupAdd extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_popupadd);
...
imageViewAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int hour = numberPickerHour.getValue();
int minute = numberPickerMin.getValue();
String activeTime = Integer.toString(hour)+":"+Integer.toString(minute);
...
// the chosen alarm Time is forwarded to the activity 'Pop Show Alarms'
PopShowAlarms popShowAlarms = new PopShowAlarms();
popShowAlarms.forwardAlarm(context, activeTime, activeDays, "motivation", "music");
finish();
}
The Mentioned interface:
public interface interfaceForwardAlarm {
void forwardAlarm(Context context, String alarmTime, String activeDays,
String motivation, String music);
}
I'd be greatful for any help. I often struggle with this problem. (Calling methods from different activities) I hope this is at least the right approach

AlarmManager reset on reboot

I've an alarm which opens an activity at a time chosen by the user. If the user hits the start button, the alarm goes fine but it gets cancelled after reboot. I've looked everywhere and it says that I should use a service. Is it possible to keep the alarms on after the reboot without using service? I'm new to coding so can you please breakdown what I need to do. Thank you
public class MainActivity extends AppCompatActivity {
Button disable;
Button start;
TimePicker timePicker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timePicker = (TimePicker) findViewById(R.id.timePicker);
disable = (Button) findViewById(R.id.disable_alarm);
start = (Button) findViewById(R.id.button);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, timePicker.getHour());
calendar.set(Calendar.MINUTE, timePicker.getMinute());
Intent intent = new Intent(getApplicationContext(),notification.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 120*1000, pendingIntent);
}
});
disable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(),notification.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
});
and Broadcast Receiver is
public class notification extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent scheduledIntent = new Intent(context, pop_up2.class);
scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(scheduledIntent);}}
Thanks
All of the active alarms are cancelled after phone is shutdown. In order to reset the alarms you need to use a separate broadcast receiver that will receive only boot completed action. The receiver then starts service that will reset all your alarms in background. Best one for you is IntentService, because it ends itself when the work is done. Of course you need to store the information about alarms somewhere in order to remember which ones to reset. You can use, for example, SQLite to store them.
In your manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and
<receiver android:name="developer.marat.apps.days.Alarms.BootCompletedReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="developer.marat.apps.days.Alarms.RestartAlarmsService"/>
Special receiver:
public class BootCompletedReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent i = new Intent(context, RestartAlarmsService.class);
ComponentName service = context.startService(i);
}
}
}
RestartAlarms:
public class RestartAlarmsService extends IntentService{
public RestartAlarmsService() {
super("RestartAlarmsService");
}
#Override
protected void onHandleIntent(Intent intent) {
// Restart your alarms here.
// open database, iterate through every alarm and set them again
}
}

How can I access MainActivity's objects or methods inside BroadcastReceiver?

I'm creating an android app that uses AlarmManager to create an alarm by playing a sound. To do this, I first create a PendingIntent, for which I have to create a class called AlarmReceiver, which extends BroadcastReceiver. In this new class, I override the onReceive method, in which I also start the sound. What I have right now works. However, as part of a bigger project, I will be later getting some data from a database. Regarding my question, this data is not important; what's important is that, after analyzing all the data, it will all come down to a boolean variable, which will be true or false. This variable will be in MainActivity and I want to access it in my BroadcastReceiver class to check it and if true, I would stop the music. I've checked many SO questions related to these, but I still haven't found a solution.
The code for the MainActivity is:
package com.example.alarmsound;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
Calendar t = Calendar.getInstance();
t.add(Calendar.SECOND, 5);
Context context = this;
AlarmManager alarmMgr;
alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.set(AlarmManager.RTC_WAKEUP, t.getTimeInMillis(), pendingIntent);
boolean result; //the variable I want to access to BroadcastReceiver class
}
}
And the code for the BroadcastReceiver class is:
public class AlarmReceiver extends BroadcastReceiver{
public AlarmReceiver() {}
#Override
public void onReceive(Context context, Intent intent) {
final MediaPlayer mp = MediaPlayer.create(context, R.raw.music);
Log.d("Music", "It went here.");
mp.start();
//here, I want to access result
}
}
I would really appreciate any help.
In MainActivity:
Intent intent = new Intent(this, AlarmReceiver.class);
intent.putExtra("some_constant", result);
In your broadcast receiver:
boolean result = intent.getBooleanExtra("some_constant", false);
Create an instance of your MainActivity and get it using a method, add following code in your MainActivity:
private static MainActivity instance;
#Override
protected void onStart() { // onStart() of your activity
super.onStart();
instance = this;
}
public void yourMethod(){
// Your code here
}
public static MainActivity getInstance(){
return instance;
}
Now, in your BroadcastReceiver, you can get the instance using:
MainActivity obj = MainActivity.getInstance();
And you can call your method using:
obj.yourMethod();

Broadcast Data using Alarm Manager

I am trying to send data to my parse SDK Database using Alarm Manager.
I am able to send data without Alarm manager.
My below code is not working correctly as parse sdk database is not showing updated data.
Here is my code:
Main Activity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_todo);
setTitle(R.string.create_todo);
alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_FIFTEEN_MINUTES,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, alarmIntent);
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
MyAsyncTask asyncTask = new MyAsyncTask();
asyncTask.execute(new String[]{});
}
class MyAsyncTask extends AsyncTask<String,Void,String>
{
#Override
protected String doInBackground(String... params) {
try {
ParseObject parseObject = new ParseObject("Todo");
parseObject.put("name", "abc");
parseObject.save();
}
catch(ParseException e)
{
}
return null;
}
}
}
Register your broadcast in AndroidManifest.xml file
Try below code:
alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + AlarmManager.INTERVAL_FIFTEEN_MINUTES , AlarmManager.INTERVAL_FIFTEEN_MINUTES, pIntent);
From above code, Below things will be happened.
first time Broadcast will be fired after 15 min. then it will be fired every 15 min.

Unable to cancel the alarm from AlarmManager

I have an AlarmManager that notifies me every 10 seconds. Everything works just fine but for some reason I can't cancel the alarm. Here's my code.
public class AlarmNotifReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
//things
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10*1000, pi); // Millisec * Second
}
public void CancelAlarm(Context context)
{
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
}
}
as expected I call this CancelAlarm() method from my other classes but for some reason it does not cancel and keep notifying me like nothing happened.
Note: SetAlarm() also works just fine.
Thanks in advance.
Alarm should be created and cancelled on Same Pending intent.In your case you are creating Pending Intent Twice.
Your code should look like below.
public class AlarmNotifReceiver extends BroadcastReceiver {
PendingIntent pi;
AlarmManager am;
Intent i;
#Override
public void onReceive(Context context, Intent intent) {
pi = PendingIntent.getBroadcast(context, 0, i, 0);
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
i = new Intent(context, AlarmNotifReceiver.class);
//things
}
public void SetAlarm(Context context) {
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10 * 1000, pi);
}
public void CancelAlarm(Context context) {
am.cancel(pi);
}
}
Try to cancel Pendingintent--
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT).cancel();
Hope this helps
Try this.
Android: Get all PendingIntents set with AlarmManager
To cancel all alarm, first you have to find all the pending intent for that and cancel alarm using that.
Try like this
public class AlarmNotifReceiver extends BroadcastReceiver {
AlarmManager am = null;
#Override
public void onReceive(Context context, Intent intent)
{
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
//things
}
public void SetAlarm(Context context)
{
am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10*1000, pi); // Millisec * Second
}
public void CancelAlarm(Context context)
{
am.cancel(pi);
}
}
Your problem is that you're creating a NEW intent instead of cancelling the existing one. Function SetAlarm should place the intent into a "global" variable and the CancelAlarm function should just call
am.cancel(global_pi);
The above worked for me in a service, but:
If this is impossible (since that's a Receiver), try setting a new alarm with the (new) intent first.

Categories

Resources