Periodically obtaining/updating and comparing data in android? - android

I am creating an android application which obtains the local weather forecast from a weather api as well as twitter updates on the aurora borealis and correlates the two. I was wondering what is the best way for me to continually update the data and compare it, even when the user does not have the application open on their device? So essentially I want my app to run in the background. Any help would be great!

The task you want to repeat periodically may be implemented in a IntentService.
public class MyService extends IntentService {
public MyService () {
super("MyService ");
}
#Override
protected void onHandleIntent(Intent intent) {
new MyTask().execute();
Log.d("MyService", "About to execute MyTask");
}
private class MyTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... strings) {
Log.d("MyService", "Calling doInBackground within MyTask");
return false;
}
}
}
You need to set a periodic alarm through the AlarmManager, that allow you to decide when to start the IntentService using a PendingIntent; for example, in an activity:
...
int interval =10*1000;//every 10 seconds
AlarmManager alarm = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, MyAlarmReceiver.class);
PendingIntent pendingIntent =PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
interval, pendingIntent);
...
The PendingIntent will be sent to an BroadcastReceiver listening for the alarm:
public class MyAlarmReceiver extends BroadcastReceiver {
public MyAlarmReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, MyService.class);
context.startService(serviceIntent);
Log.d("MyAlarmReceiver", "Called context.startService");
}
}
Everytime phone is turned off, the alarms you set are automatically canceled, so you need a BroadcastReceiver listening for boot_completed e setting again the alarm:
public class MyBootReceiver extends BroadcastReceiver {
public MyBootReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d("MyBootReceiver ", "Boot completed");
int interval =10*1000;//every 10 second
AlarmManager alarm =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context, MyAlarmReceiver.class);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(),
interval, pendingIntent);
}
}
In AndroidManifest.xml you need to add the RECEIVE_BOOT_COMPLETED permission and the BOOT_COMPLETED intent-filter for the BroadcastReceiver :
<application ...>
...
<receiver
android:name=".services.MyBootReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter android:priority="500" >
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
...
</application>
...
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
More detail here

Related

Alarm not triggering in android

I am new to android programming. What am i doing wrong? AlarmReceiver class not triggering...I want to trigger repeatedly the AlarmReceiver.class ...
I used the code from this page https://developer.android.com/training/scheduling/alarms#precision
OnCreate at MainActivity.java i have the following code
AlarmManager alarmManager = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this,AlarmReceiver.class);
//Check if the PendingIntent already exists
PendingIntent pendingIntent =
PendingIntent.getService(this, 6661, intent,
PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null && alarmManager != null) {
//cancel here if you want
}
//Run every 60 seconds!
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 60000,
60000, pendingIntent);
The AlarmReceiver.java class includes the following code...
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// For our recurring task, we'll just display a message
Log.i("logit","testing...");
}
}
Do you have an entry in your manifest for the receiver like that?
<receiver android:name=".AlarmReceiver"></receiver>

AlarmManager keeps bringing activity to foreground

I'm trying to write code that will run in the background and call server APIs. Googling led me to use AlarmManager, here is my code:
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 4000;
Intent alarmIntent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
The problem here though, is when my app is on the foreground (currently in android main menu, or on another app), whenever the alarm fires, it sends my activity to the front.
Anyone know why this happens and how I can avoid this? I have a service that is started by the AlarmReceiver class, and I want it to run on the background.
AlarmReceiver.class:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LogService.class);
i.putExtra("param1", "index.html");
i.putExtra("param2",
"http://www.vogella.com/index.html");
context.startService(i);
}
}
LogService.class
public class LogService extends IntentService{
public LogService() {
super("LogService");
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent intent) {
String param1 = intent.getStringExtra("param1");
String param2 = intent.getStringExtra("param2");
Log.i("Hello from logservice!", "!!! -- " + param1 + " - " + param2);
}
}
Added stuff to manifest:
<receiver android:name="com.example.app.alarm.AlarmReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<service android:name="com.example.app.alarm.LogService" >
</service>
Thanks in advance!
After reading around, I've found out that since API 19, all repeating alarms are inexact. After knowing about this, I tried using the setRepeating function. I don't know why it behaves differently, but all is working as intended now.

Start service on boot and repeat

im trying to do somekind of auto GoogleDrive backup(uploading a file) timer, but i cant set the specific time, even if i set to 5 seconds(testing purpouse, it just run every 1minute) and when the user reboot the phone, it only RUN one time (the Alarm is not called =/, so the application has to be opened one time after the boot)
Manifest Configuration:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application...>
<receiver
android:name=".Tools.AutoBackupAlarmBroadCast"
android:process=":remote" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".Tools.AutoBackupService"
android:exported="false" />
</application>
and with this WakeBroadCast:
public class AutoBackupBootStarter extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, AutoBackupService.class);
context.startService(startServiceIntent);
}
}
make sure that the AutoBackupAlarm is called on boot, but it only happens ONE time, i need it to start the trigger to repeat by the user setted time(will get it from shared Preferences)
the service:
AutoBackupService:
public class AutoBackupService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
*/
public AutoBackupService() {
super("AutoBackup");
}
#Override
protected void onHandleIntent(Intent intent) {
WakefulBroadcastReceiver.completeWakefulIntent(intent);
//HERE i must start the Async to make the GoogleDrive Backup
//the next doubt will be how can i get sharedpreferences and activity to pass to the async from HERE?
Log.d("BACKUP", "AutoBackupLogTest");
}
}
the broadcast
public class AutoBackupAlarmBroadCast extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, AutoBackupService.class);
i.putExtra("foo", "bar");
context.startService(i);
}
}
the AlarmFunction called on onCreate, that almost works how i want, it cant repeat every 5 seconds like the time below, it only show every 1 minute
public void scheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(getApplicationContext(), AutoBackupAlarmBroadCast.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, AutoBackupAlarmBroadCast.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
1 * 5 * 1000, pIntent);
}
Try below code to repeat task after particular time interval
boolean alarmUp = (PendingIntent.getBroadcast(this, 444, new Intent(this, AlarmReceiver.class), PendingIntent.FLAG_NO_CREATE) != null);
if(!alarmUp){
AlarmManager alarmManager = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
Intent DataSyncIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 444, DataSyncIntent, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime(),
15 * 60000, // 60000 = 1 minute,
pendingIntent);
}

Call web service in interval on background

Application need synchronize data from server in interval (for example every 30min) or manually on background. Result is saved to local database. After sync is done I want remind activity/fragment ... and force update list (if needed). There are many activities, so I want move it outside of activity and make it more consistent.
For now I created AsyncTask which get result from server and save to DB.
What shoud I use? BroadcastReciever, Service, AlarmManager?
UPDATE
Based on answers I start alarm in Application
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
manager.setInexactRepeating(AlarmManager.RTC, 0, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent);
Created Receiver
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent syncIntent = new Intent();
syncIntent.setClass(context, DataSyncer.class);
startWakefulService(context, syncIntent);
}
}
Created IntentService
public class DataSyncer extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
// get data from server
// save to DB
AlarmReceiver.completeWakefulIntent(intent);
}
}
And registered Receiver and Service in AndroidManifest
<service
android:name="com.cloudit.tsystems.app.DataSyncer"
android:enabled="true">
</service>
<receiver
android:name="com.cloudit.tsystems.app.AlarmReceiver"
android:enabled="true">
</receiver>
Where and how I notify that sync is done in Activity/Fragment?
I would use the AlarmManager and register a BroadcastReceiver. Once the receiver is fired, I will launch an IntentService to download the data in the background.
Configure your alarm:
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcast.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
manager.setInexactRepeating(AlarmManager.RTC, 0, AlarmManager.INTERVAL_HALF_HOUR, pendingIntent);
Create a BroadcastReceiver that will get notified when the alarm goes off. Note that I'm using a WakefulBroadcastReceiver so that the device doesn't go to sleep when you're syncing.
class MyBroadcast extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent syncIntent = new Intent();
syncIntent.setClass(context, DataSyncer.class);
startWakefulService(context, syncIntent);
}
}
Next, an IntentService that will download data in the background:
class DataSyncer extends IntentService{
...
#Override
protected void onHandleIntent(Intent intent) {
//sync data
MyBroadcast.completeWakefulIntent(intent);
}
}
Update:
So now that you have your data synced, there are several options to notify Activities and Fragments. You can use a LocalBroadcastManager to broadcast. Take a look at this link for more details.
Use an AlarmManager to trigger a PendingIntent on a 30 minute interval that starts an IntentService to do your download.
Intent intent = new Intent(context, PollingService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.RTC,
System.currentTimeMillis(),
AlarmManager.INTERVAL_HALF_HOUR,
pendingIntent
);
When the IntentService is done updating your data, it can send a Broadcast that your Activity/Fragment has registered to listen for to notify it of new data and refresh it's view.
sendBroadcast(new Intent("DATA_UPDATED"));
In your Fragment
getActivity().registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//update UI
}
}, new IntentFilter("DATA_UPDATED"));

Android alarm not working

I've been struggling with this for hours. I've also checked the documentation and several topics. I found this code in two topics, both guys said the code was working perfectly, but not on my computer. The first Toast appears, but the second one never. What is wrong?
public class HelloAndroid2 extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (10 * 1000), pendingIntent);
Toast.makeText(this, "Alarm set", Toast.LENGTH_LONG).show();
}
public final class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked.", Toast.LENGTH_LONG).show();
}
}
}
Actually you dont need to specify the action since you use the class AlarmReceiver.class in the intent.
In your AndroidManifest.xml, make sure you have a receiver definition within the <application> tags, something like:
<receiver android:name="AlarmReceiver">
Edit:
Ok there are 2 ways to use your broadcast receiver.
1) From the code you have provided, AlarmReceiver.java that will contains:
public final class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked.", Toast.LENGTH_LONG).show();
}
}
and HelloAndroid2.java:
public class HelloAndroid2 extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (10 * 1000), pendingIntent);
Toast.makeText(this, "Alarm set", Toast.LENGTH_LONG).show();
}
}
Like this, you can set your broadcast receiver to work with the AndroidManifest.xml and the tag <receiver ...>
2)2nd way. With this way, you can use just 1 file HelloWorld2.java:
In your activity, create your broadcast receiver and register it.
public class HelloWorld2 extends Activity {
private SharedPreferences prefs;
private String mName;
BroadcastReceiver alarmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm worked", Toast.LENGTH_LONG).show();
}
};
public static final String ACTION_NAME = "com.helloworld.MYACTION";
private IntentFilter myFilter = new IntentFilter(ACTION_NAME);
#Override
protected void onPause() {
unregisterReceiver(alarmReceiver);
super.onPause();
}
#Override
protected void onResume() {
registerReceiver(alarmReceiver, myFilter);
super.onResume();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(alarmReceiver, myFilter);
Intent intent = new Intent(ACTION_NAME);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (10 * 1000), pendingIntent);
Toast.makeText(this, "Alarm set", Toast.LENGTH_LONG).show();
}
I had the same problem until I found that I had put my Broadcast Receiver on a different package, not the general.
Simply changed:
<receiver android:name=".AndroidAlarmService" android:enabled="true" >
for:
<receiver android:name="com.MyCompany.MyPackage.AndroidAlarmService" android:enabled="true" >
If the answer above doesn't work for you then there is another way to not receive any callbacks when AlarmManager fires an expired alarm. You simply need to check this one out: by sending the wrong Intent on instantiation of PendingIntent. For example you wanted to receive a call onReceive on one of your receivers but you instantiated a PendingIntent via getActivity or getService, but what you actually meant is getReceiver.
When creating instance of PendingIntent, there are many ways to create it (getService, getActivity,getReceiver, getForegroundService:
if you want Activity the receiver of the intent then you:
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_*);
if you want BroadcastReceiver the receiver of the intent:
PendingIntent.getReceiver(this, 0, intent, PendingIntent.FLAG_*);
if you want a foreground Service the receiver of the intent:
PendingIntent.getForegroundService(this, 0, intent, PendingIntent.FLAG_*);
if you want a Service the receiver of the intent:
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_*);
Also, make sure you intents are pointing to the correct class. (e.g. creating intents for Activity, Service etc.). You will not receive any call if you pass wrongfully like this:
Intent intent = new Intent(this, MyReceiver.class); // You wanted receiver
// PendingIntent was created in such a way
// you wanted this to be received by an activity.
// you will not receive any call if you set it up like this.
PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_*);
I also posted similar answer here.
HTH

Categories

Resources