I tried to make reminder application for Android, followed tutorial from this website Set Notification for Specific Date. Basically it used Alarm Manager to create a reminder.
This code used to call alarm manager and show notification on specific date.
reminderClient.setAlarmForNotification(calendar, uniqueid, interval);
I save all of the reminder in SQLite Database. So when this code (above) called, new record will be inserted to database and when notification show up, that record will be deleted.
The problem is whenever device restart, alarm manager stopped.
So I create a new BroadcastReceiver that receive event when device turned on.
<application ... >
<receiver android:name=".ReminderReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
</intent-filter>
</receiver>
</application>
public class ReminderReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//do stuff
}
}
Is it OK to get all record from database, and call setAlarmForNotification again inside OnReceive like this?
public class ReminderReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
List<MyReminder> reminders = database.getAllReminder();
Calendar cal = Calendar.getInstance();
for (int i=0; i<reminders.size(); i++) {
cal.setTime(parseStringDateToDate(reminders.get(i).getDateTime());
reminderClient.setAlarmForNotification(
cal,
reminders.get(i).getUniqueID(),
reminders.get(i).getInterval()
);
}
}
}
Or is there a better way?
BroadcastReceiver's onReceive() is called on UI thread so in common case it's not right to access a database or do any other file I/O in this method. For this task you need two things: background thread to give the system an ability to make its stuff in parallel and a Service to tell the system that it should not kill your process when onReceive() is finished. There is a component that gives you both things - IntentService. It's a Service and a working thread that finishes and stops a Service when return from onHandleIntent().
Also posibly you will need a WakeLock to ensure that all your calculations are finished and alarms are properly set. Look at WakefulBroadcastReceiver that is written just for this case.
NOTE: Actually in your case file I/O is really minimal and system boot probably is not a moment when every hundred milliseconds are crucial. But there is really no reason not to do things right.
Related
I have been trying to develop this features for days and just keep getting errors and bugs. I am making an app that will notify users when it's time to pray. I have all the prayer times inside a db downloaded from a server in json format. The data is all correct as I have checked multiple times.
I have created a Service that will set Alarm using AlarmManager.
Then I bind my MainActivity to the Service. From the main activity I set Alarm using a method from the service called setAlarmAccordingToDB().
The problem is when I bind my service. The service gets destroyed when app is closed. Upcoming notifications are not notified.
Then I tried to start the service and bind it to my activity.Called setAlarmAccordingToDB(). What happened was setAlarmAccordingToDB was called repeatedly. It kept setting up new alarms non-stop.
Any advice on how upcoming notifications should be set?
You probably need to use a Wakeful service, so the device/process wakes up when the alarm is called.
I have used this code for a while in my app (not the project, just modified my code from Mark's examples) with great results.
https://github.com/commonsguy/cwac-wakeful
I tried to use a separate class for broadcastReceiver and it seems to work. I just used Alarm Manager and BroadcastReceiver. After the revised code, my app could fire the notifications even when the phone screen is turned off and app closed.
Before this i used:-
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
displayNotification();
}
};
Now, I created a class:-
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager;
notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
displayNotification(context);
}
}
In the AndroidManifest.xml I added
<receiver android:name=".Receiver" android:process=":remote"></receiver>
I am currently trying to create an app that can track how much time I spend in a phone call and then display that on a toast message after clicking a button.
Code found here: http://paste.ideaslabs.com/show/6INd0afyi
I can't seem to figure out why the app is not working...
The idea is to create a service that starts as soon as I make a phone call (and keeps running indefinitely from then on). The Service has two while loops that track the start time and end time of the conversation using the getCallState() method through the TelephonyManager class. And then the values the end time and start time variables are stored and used in the activity class.
The activity class simply uses a button to display a toast message that says how much time I have spent.
When I try to run the app on my phone I can see the service running, but the app crashes sometimes or just shows that the time spent calling is 0 mins (which is not true..)
Hope you guys can point out any mistakes?!
Thanks!
Just by seeing the code you have posted I would say that you have not read properly the docs about services. You don't create a service by doing a MyService s = new MyService()
Read the Android developer guide or the Android SDK documentation. You'll see for instance how to start a local service or to use intents to start a service.
E.g.:
Intent intent = new Intent(this, HelloService.class);
startService(intent);
There are some events that the Operating System broadcast when they happen. eg. receiving sms, phone call state( sending, receiving). By reading your post, i think you should register your app with broadcast receiver. Here is a sample code.
public class PhoneCallState extends BroadcastReceiver
{
static long start_time, end_time;
#Override
public void onReceive(Context context, Intent intent)
{
final Bundle extras = intent.getExtras();
if(intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED))
{
final String state = extras.getString(TelephonyManager.EXTRA_STATE);
if ("RINGING".equals(state))
{
Toast.makeText(context, "Ringing", Toast.LENGTH_LONG).show();
}
if ("OFFHOOK".equals(state))
{
start_time = System.currentTimeMillis();
Toast.makeText(context, "Off", Toast.LENGTH_LONG).show();
}
if ("IDLE".equals(state))
{
end_time = System.currentTimeMillis();
long duration = (end_time - start_time) /1000;
Toast.makeText(context, "Duration : " + duration, Toast.LENGTH_LONG).show();
}
}
}
And register your receiver in the manifest file.
<receiver android:name=".PhoneCallState">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
}
Finally don't forgate to add a PHONE_STATE Permission.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Looking at your previous questions I suggest reading this: How to make a phone call in android and come back to my activity when the call is done?
It describes how to set up a PhoneStateListener so that you can receive an intent when a call is started locally, received from someone else, and ended.
The Service has two while loops that track the start time and end time
These while loops are unnecessary with a PhoneStateListener, you can simply get two time stamps and subtract the difference, without having two while loops running every millisecond.
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.
As my code looks today, I'm periodically sending a alarm(?) using AlarmManager that is received by AlarmReceiver extends BroadcastReceiver which in turn starts a Service. The Service do some updating and ends with a stopSelf(). IMO this is the best way of periodically perfom a task without constantly having a Service running. Correct?
The issue with this code is however that the whole chain of events is initiated onSharedPreferenceChanged(). I (initially) thought this was a good idea since the whole updating thing is enabled by the user in SharedPreferences.
I've now come to the conclusion that this is in fact not very good and that I need to initiate the AlarmManager/AlarmReceiver/Service/whatever both onPreferenceChange but also on boot.
I've done some searching but everyone seems to want to start the Service on boot. As I see it, I just need to initiate the AlarmManager which will then start the Service (when needed and only periodically).
Please help me with, first of all, sorting this out and secondly coding it!
Thanks in advance!
Then, create and register a BroadcastReceiver where you will do the AlarmManager stuff:
public class YourBootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// do the AlarmManager here
}
}
Then, on your manifest:
<application>
... other stuff
<receiver android:name=".YourBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
How can I execute an action (maybe an Intent) on every specified time (e.g. Every day on 5AM)? It has to stay after device reboots, similar to how cron works.
I am not sure if I can use AlarmManager for this, or can I?
If you want it to stay after the device reboots, you have to schedule the alarm after the device reboots.
You will need to have the RECEIVE_BOOT_COMPLETED permission in your AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
A BroadcastReceiver is needed as well to capture the intent ACTION_BOOT_COMPLETED
<receiver android:name=".BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Lastly, override the onReceive method in your BroadcastReceiver.
public class BootcompletedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//set alarm
}
}
Edit: Look at the setRepeating method of AlarmManager to schedule the 'Android cron'.
Using the BuzzBox SDK you can schedule a cron job in your App doing:
SchedulerManager.getInstance()
.saveTask(context, "0 8-19 * * 1,2,3,4,5", YourTask.class);
Where "0 8-19 * * 1,2,3,4,5" is a cron string that will run your Task once an hour, from 8am to 7pm, mon to fri.
You Task can be whatever you want, you just need to implement a doWork method. The library will take care of rescheduling on reboot, of acquiring the wake lock and on retrying on errors.
More info about the BuzzBox SDK here...