In my app, I want to send sensor data every ten seconds via POST to a webserver.
I am doing this with an activity who starts/stopps a AlarmMananger who is calling an IntentService.
Problem is: the target URL is generated in the Activity and doesn't arrive at the IntentService.
Activity:
public class MyActivity extends AppCompatActivity {
...
#Override
protected void onResume() {
super.onResume();
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE);
String targetURL = "www.google.de";
alarmIntent.putExtra("targetURL", targetURL);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10000, pendingIntent);
}
...
}
Broadcast-Receiver:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String targetURL = intent.getStringExtra("targetURL");
Intent newintent = new Intent(context, SendPostRequest_Service.class);
newintent.putExtra("targetURL", targetURL);
context.startService(newintent);
}
}
Intent Service:
public class SendPostRequest_Service extends IntentService implements SensorEventListener{
...
public SendPostRequest_Service() {
super(SendPostRequest_Service.class.getName());
}
#Override
protected void onHandleIntent(Intent intent) {
String targetURL = intent.getStringExtra("targetURL");
// Problem: targetURL = null
//read sensors, send POST-Request via okhttp <- working
}
...
}
Do you have any suggestions?
Put your code into a test project. Only way I was able to get it working was to change the order of when the extra is added to the intent. Update MyActivty with the below. It would appear to G. Blake Meike point that there's a copy of the intent being done.
#Override
protected void onResume() {
super.onResume();
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
String targetURL = "www.google.de";
alarmIntent.putExtra("targetURL", targetURL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10000, pendingIntent);
}
You'll need to take a wake lock in your BroadcastReceiver and release it in your Service. Otherwise, the system may return to a sleep state before your Service gets a chance to run. The WakefulReceiver is particularly useful for this. If you'd like some more details, this article will help: http://hiqes.com/android-alarm-ins-outs/
Related
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>
I have a MainActivity that starts a class HintergrundDienst extending Service by pressing a button btnStartStop on the MainGUI of MainActivity with
Intent inte = new Intent(getApplicationContext(), HintergrundDienst.class);
Bundle ints = new Bundle();
ints.putInt....
inte.putExtras(ints);
startService(inte);
MainActivity and HintergrundDienst both have a
PlayerClass pcObject = new PlayerClass();
Now
public class PlayerClass extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
///
}
public void abbrechen(Context context, long requestCode)
{
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent myIntent = new Intent(context.getApplicationContext(), PlayerClass.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context.getApplicationContext(), (int)requestCode, myIntent, 0);
alarmManager.cancel(pendingIntent);
}
public void alarmieren(Context context, long requestCode, int ResID)
{
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
...
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, (int)requestCode, intent, PendingIntent.FLAG_ONE_SHOT);
alarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, requestCode, pendingIntent);
}
}
I set alarms in HintergrundDienst with audioAbspielen.alarmieren(this,time.getTimeInMillis(),R.raw.test);.
My goal is to press btnStartStop once for it to start and btnStartStop again for it to stop all alarms. My issue is that to stop an alarm, I need requestCode. I'd have to put all requestCodes into a List in PlayerClass. But I cannot access this List from MainActivity where btnStartStop is directly. But I could expose it via method in PlayerClass. But how I see it, the pcObject in MainActivity is not the one as in HintergrundDienst. So the list being filled in HintergrundDienst might be null or empty in MainActivity.
In short: how do I cancel all alarms in this context?
You can use SharedPreferences to save the value of requestCode when calling alarmieren, and retrieve it back to cancel.
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"));
I want to start a service when wifi network connected.
If I start the service when wifi connected, by using
context.startService(intent_alarm);
it works fine.
I want to start the service for every 10 seconds after recieving broadcast. So I have used AlarmManager
Here is the code:
public class NetworkChangeReceiver extends BroadcastReceiver{
public static AlarmManager am;
public static PendingIntent sender;
#Override
public void onReceive(final Context context, final Intent intent) {
Intent intent_alarm = new Intent(context, MyService.class);
sender = PendingIntent.getBroadcast(context, 0, intent_alarm, 0);
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long l = System.currentTimeMillis();
l += 3600L;
am.setRepeating(AlarmManager.RTC_WAKEUP,l, 3600L, sender);
//context.startService(intent_alarm);
}
}
I think here I gave 3.6 seconds as the intervel.
But the service not running, I checked it manually.
Please tell me what I'm doing wrong?
You need to tell the alarm manager to start your service:
Intent intent_alarm = new Intent(context, MyService.class);
sender = PendingIntent.getService(context, 0, intent_alarm, 0);
you have used PendingIntent.getBroadcast instread of PendingIntent.getService
so use this - >
Intent intent_alarm = new Intent(context, MyService.class);
sender = PendingIntent.getService(context, 0, intent_alarm, 0);
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