IntentService can't be invoked from BroadcastReceiver - android

I need to update my app's contnent everyday and I use AlarmManager, BroadcastReceiver and IntentService for it.
I create AlarmManager object and setRepeating in the class that extends from Application class:
private void setRecurringAlarm(Context context) {
Intent intent = new Intent(AlarmReceiver.ACTION_ALARM);
AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pIntent = PendingIntent.getBroadcast(this,
1234567, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarms.setRepeating(AlarmManager.RTC,
System.currentTimeMillis(), 10000, pIntent);
Toast.makeText(getApplicationContext(), "started", Toast.LENGTH_SHORT).show();
}
My BroadcastReceiver get's message successfully :
public class AlarmReceiver extends BroadcastReceiver {
private static final String DEBUG_TAG = "AlarmReceiver";
public static String ACTION_ALARM = "com.alarammanager.alaram";
#Override
public void onReceive(Context context, Intent intent) {
Intent downloader = new Intent(context, UpdateService.class);
downloader.setAction(Constants.UPDATE_SERVICE);
context.startService(downloader);
Toast.makeText(context, "Entered", Toast.LENGTH_SHORT).show();
}
}
But I also need to start IntentService from the BroadcastReceiver, but it don't started from onReceiver's method of BroadcastReceiver. My service:
<service android:name="com.services.UpdateService"
android:enabled="true">
<intent-filter>
<action android:name="com.service.UpdateService" />
</intent-filter>
</service>
And class for it.
public class UpdateService extends IntentService {
public UpdateService() {
super("UpdateService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("UpdateService", "About to execute MyTask");
// new MyTask().execute();
Toast.makeText(getApplicationContext(), "updateService", Toast.LENGTH_SHORT).show();
}
// Sometimes overriding onStartCommand will not call onHandleIntent
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("asdasd", "here..!");
return super.onStartCommand(intent,flags,startId);
}
}
My question is why does it(IntentService) can't be invoked from BroadcastReceiver.

Called by the system every time a client explicitly starts the service
by calling startService(Intent), providing the arguments it supplied
and a unique integer token representing the start request. Do not call
this method directly.
If you do call then this is the preferred way:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleCommand(intent);
return START_REDELIVER_INTENT;
}

Related

Local Notification after App killed using Alarm manager in android 10

I want to show local notification on specific time. So that I am using alarm manager to set pending intent for specific time. But in my case Broadcast/Service is not getting called if application killed by user.
Check the below code and help me out why am not getting notification after application killed.
public class MainActivity extends AppCompatActivity {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent notifyIntent = new Intent(this,MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(MainActivity.this, 1, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+30000, pendingIntent);
}
}
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, MyNewIntentService.class);
context.startService(intent1);
}
}
public class MyNewIntentService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
CommonUtil.showNotification(getApplicationContext());
return START_STICKY;
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="false"
/>
<service
android:name=".MyNewIntentService"
android:exported="false"
/>
You can check here for working sample of Alarm with Broadcast receiver.
How to use Android AlarmManager in Fragment in Kotlin?

How do I implement a periodic Task that queries the db and deletes row periodically?

How do I implement a periodic Task that queries the db and deletes row periodically? I want to do this so that I prevent my database from growing too big over time.
Using a Sticky Service with AlarmManager and BroadcastReceiver is what you need.
public class MY_SERVICE extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// remove last alarm you set
Intent intent = new Intent(context, MY_DB_PROCEDURE_BROADCAST.class);
intent.setAction("myDbProcedure");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context,1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.cancel(alarmIntent);
// add new alarm manager
intent = new Intent(context, MY_DB_PROCEDURE_BROADCAST.class);
intent.setAction("myDbProcedure");
alarmIntent = PendingIntent.getBroadcast(ct, 1, intent, 0);
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(),
intervalMin*60*1000, alarmIntent);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
your BroadcastReceiver class :
public class MY_DB_PROCEDURE_BROADCAST extends BroadcastReceiver {
private final String TAG=getClass().getName();
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG,"Started");
// DO YOUR DB TASK HERE
}
}
In your manifest define the service and broadcastReceiver:
<service
android:name="MY_SERVICE"
android:enabled="true"
android:exported="true" />
<receiver android:name="MY_DB_PROCEDURE_BROADCAST" android:enabled="true"/>

SendBroadcast() doesn't work in on receive of Broadcast

I have the main activity, that execute a service. In this service, I init a BroadcastReceiver (alarm).
Then I need send briadcast from the onReceive method of alarm broadcst, but doesn't work. But if I execute sendBroadcast() of other method in alarm, work perfectly.
See de code for explain me:
Activity (init service and get broadcastReceiver)
private final BroadcastReceiver abcd = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Intent in = getIntent();
//finish();
Log.d("sdasd", "onReceive: BROADCAST RECIBIDO!!!");
}
};
Service
alarm alarm = new alarm();
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
alarm.setAlarm(this, tiempo);
return START_STICKY;
}
Alarm.class
#Override
public void onReceive(Context context, Intent intent)
{
context.sendBroadcast(new Intent("xyz"));
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
}
public void setAlarm(Context context, int tiempo)
{
Log.e("TAG", "setAlarm: ");
context.sendBroadcast(new Intent("xyz"));
AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), tiempo, pi); // Millisec * Second * Minute
}
In alarm.class, the sendBroadcast in serAlarm() is executed, but the sendBroadcast in onreceive, doesn't executed. And the toast work perfectly.
Why?
I guess, you need to regist BroadcastReceiver in Service.class.
You can regist BroadcastReceiver in 2 way;
AndroidManifest.xml use
<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="xyz"/>
</intent-filter>
</receiver>
Sourcecode :
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("xyz");
registerReceiver(abcd, intentFilter);
private final BroadcastReceiver abcd = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Intent in = getIntent();
//finish();
Log.d("sdasd", "onReceive: BROADCAST RECIBIDO!!!");
}
};
======
".TestReceiver" example: It is Java Class File
public class TestReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
}}

Best way to run a never ending service in Android

I have a service that gives a notification if user has changed his location. I want this service to keep on running until user explicitly force stops my application in application manager. I have used following method:
Intent intent1 = new Intent(context, LocationService2.class);
PendingIntent contentIntent = PendingIntent.getService(context, 0, intent1, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),2*60000, contentIntent);
Service class:
public class LocationService2 extends Service implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("TAG", "STARTLS");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
return START_STICKY;
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Location services connected.");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
// Use this location to give notification if required.
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
}
}
This method does not work on all phones.
Is AlarmManager the best way to do this. If yes, then how can I improve this code to work on all phones?
You should make your service a Foreground Service. You can find a tutorial here.
Manifest Entry
<receiver android:name="YourPackagename.RestartReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="YourPackagename.AlarmReceiver" >
</receiver>
On phone reboot need to reinitialize alarm manager
RestartReceiver.java
public class RestartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intentReciever = new Intent(context, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intentReciever, 0);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + GlobalContext.PUSH_NOTIFICATION_INTERVAL),
GlobalContext.PUSH_NOTIFICATION_INTERVAL, alarmIntent);
}
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//you can put your logic over here
}
}
Put below code in your Splash Screen
private void initService() {
if(!app_preferences.getBoolean("isServiceRunning", false))
{
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intentReciever = new Intent(LoadingScreen.this, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(LoadingScreen.this, 0, intentReciever, 0);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis()+GlobalContext.PUSH_NOTIFICATION_INTERVAL),
GlobalContext.PUSH_NOTIFICATION_INTERVAL, alarmIntent);
app_preferences.edit().putBoolean("isServiceRunning", true).commit();
}
}
//Note: its not good way to check your Alerm service using shared preference is running or not.
The steps to make a never ending service are :
1.) Start service using alarmManager.
2.) Check in onResume if service is running & restart if not.
3.) Return START_STICKY from onStartCommand().
4.) In OnStartCommand() , create a thread and do the needful from that thread .All the logical stuff should be there in while(true).
This way your service will never be killed .
In given code i have put some good things like you can communicate with activity using binder service via listner. You can notify your activity that you lost internet connction by writing code in service...
Create service as sticky which will never end. if user will kill app it will again automatically restart.
When compare to alarm manager you may face duplication/multiple service get started. like we need to identify and prevent that if Alarm manager already i have created then don't start again as per my another answer written in same question.
Manifest.xml
<receiver android:name=".BootCompleteReceiver"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver>
<service android:name=".MyService" android:enabled="true" android:exported="false"/>
MyService.java
public class MyService extends Service {
CommunicationListner listener;
public class LocalBinder extends Binder {
public MyService getService() {
// Return this instance of LocalService so clients can call public methods
return MyService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
unregisterReceiver(internetConnectionReceiver);
} catch (Exception e) {
}
registerReceiver(internetConnectionReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
//communication with activity
public void registerChatReceivedListener(CommunicationListner listener) {
this.listener = listener;
}
public void removeChatReceivedListener() {
chatListener = null;
}
private BroadcastReceiver internetConnectionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
public MyService() {
}
}
To restart your service on restart phone
BootCompleteReceiver.Java
public class BootCompleteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
context.startService(new Intent(context, MyService.class));
}
}
}
Put code in you splash screen to start myservice if its already started then also no need to worry.
startService(new Intent(getApplicationContext(), MyService.class));
Start the service anytime it got killed.
#Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.disconnect();
startService(new Intent(this, LocationService2.class));
}
The solutions in android 5 and higher is using AlarmManger and Broadcast Receiver

BroadcastReceiver not triggered by Alarm

I am trying to set up an alarm that will run in the background and trigger (eventually) a save event. At the moment I simply have this code attached to a button. Press the button and the alarm should start leaving Toast messages behind as an indication that it is functioning. At the moment everything runs except the onReceive in the BroadcastReceiver is never triggered.
Here is my code:
The class setting up the alarm:
//FIXME - rename (ie BackgroundSave; more descriptive)
public class AlarmReceiver extends Service{
//FIXME - make sure you kill the service
public void onCreate() {
super.onCreate();
Toast.makeText(getApplication().getApplicationContext(), "Service onCreate called", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(getApplication().getApplicationContext(), "Service started", Toast.LENGTH_SHORT).show();
setAlarm(AlarmReceiver.this);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
public void setAlarm(Context c) {
AlarmManager alarmManager = (AlarmManager)c.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(c, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(c, 0, i, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMillis() + 1000, 1000, pi);
Toast.makeText(c.getApplicationContext(), "setAlarm called", Toast.LENGTH_SHORT).show();
}
public void cancelAlarm(Context context) {
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
Here is the BroadcastReceiver:
public class Alarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm", Toast.LENGTH_SHORT).show();
}
}
And here is my manifest:
<!-- Alarm -->
<service android:name="com.xxxx.android.tools.AlarmReceiver" android:enabled="true" />
<receiver android:name="com.xxxx.android.tools.Alarm" ></receiver>
The alarm onReceive is never triggered.
You have to use android.os.SystemClock.elapsedRealtime() as your base time when using AlarmManager.ELAPSED_REALTIME_WAKEUP.
That said i think to use the AlarmManager for your saving purpose is not the best approach. The alarm manager is pretty heavyweight. You should consider using a simple Handler to trigger your save action.
Have a look at Handler.postAtTime().

Categories

Resources