I know there is a lot of questions about this but I really don't know where is my mistake.
My service is registered in the AndroidManifest.xml file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.app" >
...
<service android:name="com.example.android.app.ScheduledService">
</service>
</application>
</manifest>
My service extends IntentService
public class ScheduledService extends IntentService {
public ScheduledService() {
super("ScheduledService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(getClass().getSimpleName(), "I ran!");
}
}
My Activity starts the service
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(getClass().getSimpleName(), "Setting alarm!!");
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, com.example.android.app.ScheduledService.class);
PendingIntent pending = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
10 * 1000, pending);
}
}
I don't see any exception in the logs. Is there something else I should do to setup my alarm?
As in documentation, PendingIntent.getBroadcast() is used to retrieve a PendingIntent that will perform a broadcast, like calling Context.sendBroadcast().
You need to call PendingIntent.getService() instead, which will start IntentService:
PendingIntent pending = PendingIntent.getService(this, 0, alarmIntent, 0);
Look closely at the AlarmManager API and the PendingIntent. The AlarmManager.set() API is expecting a broadcast intent, which you are providing. However, you're trying to send a broadcast intent to a service, which cannot be done. Just create a BroadcastReceiver to catch the Intent and your BR should then start your service.
The API says:
typically comes from IntentSender.getBroadcast().
that means PendingIntent.getService can work too.
I tested it, and it works.
Related
I have created one service which I want to call periodically through AlarmManager. I have written code for same, But it's not calling. If I call BroadcasrReciever through AlarmManager, then it's working fine.
Below is my Code,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Intent alarmIntent = new Intent(this, LocationUpdateService1.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.setRepeating(AlarmManager.RTC_WAKEUP, 20000, 11000, pendingIntent);
}
My service class is,
public class LocationUpdateService1 extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "I created", Toast.LENGTH_LONG);
return null;
}
}
My manifiest file,
<service
android:name=".Services.LocationUpdateService1">
</service>
Do I have to create BroadcastReceiver class to call my service ?
What is wrong in my code ? and why it's not calling periodically ?
Make sure you don't use PendingIntent.getBroadcast, it wouldn't work. Using getService() instead, like this:
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarmIntent, 0);
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/
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 have code which is to be run daily; for this I'm trying to use AlarmManager. This is my code for triggering alarms:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent i = new Intent(this, AlarmReciever.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pi); // cancel any existing alarms
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY,
AlarmManager.INTERVAL_DAY, pi);
}
This part of the code is calling AlarmReciever class as expected, but I want the code in the AlarmReciever class to be executed only once daily. It's being called multiple times. How do I restrict it?
This is the AlarmReciever class:
public class AlarmReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("in alarm reciever class");
}
}
I'm trying to perform some business logic in the onReceive() method.
In the manifest.xml file:
<receiver android:name="com.xyz.reciever.AlarmReciever"></receiver>
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
are declared.
I believe the code you should be using to set your alarm would be this:
Intent i = new Intent(this, AlarmReciever.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0); // <- HERE!!
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pi); // cancel any existing alarms
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_DAY,
AlarmManager.INTERVAL_DAY, pi);
since your AlarmReciever is a BroadcastReceiver. Use PendingIntent.getBroadcast().
If you have much work to do in your receiver's onReceive() method, you might also delegate it to an IntentService. See this answer if you decide to do that.
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