I created a BroadcastReceiver and it runs only when my app shown in recent apps menu. If I remove my app from the recent apps the BroadcastReceiver will stop working.
How can I keep the BroadcastReceiver in background?
I register the BroadcastReceiver from my main activity (in OnCreate()).
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, intentFilter);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
This is not how you should register a receiver. You receiver stops working, because you construct it in onCreate, which means it will live as long as your app is alive. When the app gets destroyed, you also lose the the receiver.
If you register receiver inside an activity, you should always register it in onResume and deregister onPause, which will make it available while the activity is visible to the user. This is a use case when you want to have an active receiver while user interacts with an activity.
If you want a background receiver, you need to register it inside the AndroidManifest (with intent filter), add an IntentService and start it when you receive a broadcast in the receiver.
Here is a tutorial, you are interested in chapter 3.
If you need to be always on, start a foreground service. There is function in Service that lets you: startForeground. Then register your receiver when service is created and deregister when it's destroyed. Foreground services are quite nasty though.
Use a service with it.
Services can survive when the app dies if they have the right flag example:
public class MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY; //this defines this service to stay alive
}
#Override
public void onCreate() {
super.onCreate();
appStatus = APPISUP;
//This is a thread that stays alive for as long as you need
new CheckActivityStatus().execute();
//Not needed but in case you wish to lauch other apps from it
}
private class CheckActivityStatus extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... params) {
while(true) {
... //add something that breaks eventually
}
}
}
To lauch the service you have to lauch it from an activity like so:
Intent service = new Intent(getBaseContext(), MyService.class);
startService(service);
With the service the BroadcastReceiver still functions receiving whatever you want.
Note that the service sometimes stops and comes back. I haven't found out why but I'm betting on priorities of other apps that may ask the system to halt the service
Related
I need to have a two way communication between my activity and a running IntentService.
The scenario is like this: the app can schedule alarms which on run, start an IntentService which fetches some data from web and process it. There are three possible situations when IntentService finishes:
The app is in focus, which means that when the IntentService will finish, the app needs to refresh its views with the new data.
The app is closed and when opened after IntentService has finished the work, so the app will have access to processed data
The app is opened while the IntentService is running, in which case I need to have a way from the activity to ask the IntentService if its doing something in the background.
For 1. I have already implemented a BroadcastReceiver in my activity which gets registered with the LocalBroadcastManager. When IntentService finishes the work, sends a broadcast and the activity reacts. This works fine
For 2. There is nothing needed to be done
For 3. I don't know what to do. So far I've tried this:
In Activity:
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_SEND_TO_SERVICE));
In IntentService
private LocalBroadcastManager localBroadcastManager;
private BroadcastReceiver broadcastReceiverService = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BROADCAST_SEND_TO_SERVICE)) {
//does not reach this place
//Send back a broadcast to activity telling that it is working
}
}
};
#Override
protected void onHandleIntent(Intent intent) {
localBroadcastManager = LocalBroadcastManager.getInstance(context);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_SEND_TO_SERVICE);
localBroadcastManager.registerReceiver(broadcastReceiverService, intentFilter);
.... //do things
}
The problem with my implementation is that n the IntentService the BroadcastReceiver does not fire onReceive. Any suggestions or maybe a simpler way for the Activity to ask the IntentService what it is doing?
LE:
Trying to get atomicboolean.
In Service:
public static AtomicBoolean isRunning = new AtomicBoolean(false);
#Override
protected void onHandleIntent(Intent intent) {
isRunning.set(true);
// do work
// Thread.sleep(30000)
isRunning.set(false);
}
In Activity, restarting the app while service is running:
Log(MyIntentService.isRunning.get());
//this returns always false, even if the intent service is running
On AndroidManifest
<service
android:name=".services.MyIntentService"
android:exported="false" />
now i have a server class that i run on a thread from an activity(i.e servActivity).now when i am not interacting with my app in anyway possible (like i have removed it from recent apps etc) the thread should stop which currently is not stopping. So i researched and i found that i should use a bound service. now a bound service i will have to bind it to servActivity and when servActivity is destroyed i have to unbind and stop service but i dont want to do that. i want to stop service when i am not interacting with the app. i also found that maybe i have to extend application class but cannot find the solution to achieve this?Is it advisable to extend the application class?
i want to be able to create a service running on independent thread from a particular activity(ie servActivity) and then be able to interact with the service from any activity and service should be active (even if the activity in which i started the service i.e-servActivity is destroyed by going to previous activity etc) through button or whatever until i am not interacting with the app(i have a notification controller which also needs to be closed to stop the interaction)
i have a client class on one device whose object i create again and again if i have to make request but i want to make only one object for server class because it has a while(true) loop so it keeps running so i want to be able to interact with the server from all activities and stop it when i am not interacting with the application
i also found a way in which i can make an abstract class which extends activity and extend that derived class to all the other activities in my app.But how to i bind the service to all the other activities in the class so that i can interact with the service from all the other activities?And how would i know that if all activities and notification controller have been stopped and there is no interaction with user?something like this how to know our app has gone to background in android
If there is there any other method please suggest
Please help
thanks in advance
You can create a BroadcastReceiver in your Service Class to interact/start/close your Service from any Activity or even from any App.
Your Activities can broadcast custom Action Strings which can be picked up by any BroadcastReceivers (even ones set up in Services) and thereby invoking their onReceive() methods allow communication.
1) I suggest you don't bind your Service to any Activity and instead use Intent to initiate it in your Activity like this....
//In your Activity
Intent i = new Intent(this, /*MyServiceClassName.class*/);
startService(i);
Or else your Service may still be active until you unbind it.
2) Create a BroadcastReceiver in your Service Class to listen for certain Action Strings broadcasted by your Activities....
//In your Service
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(/*"Action String to stop Service"*/)){
stopSelf();
}else if(action.equals(/*"Action string to interact with Service"*/)){
//Do what you want
};
3) Now set what Action Strings the Broadcast Receiver will listen for and also register it in your Service onCreate() method....
//In your Service onCreate() method
IntentFilter filter = new IntentFilter();
filter.addAction(/*"Action String to stop Service"*/);
filter.addAction(/*"Action String to do something"*/);
registerReceiver(receiver, filter);
4) And also unregister your receiver when Service onDestroy() is invoked as housekeeping....
//Service onDestroy()
#Override
public void onDestroy(){
super.onDestroy();
unregisterReceiver(receiver);
}
5) Finally broadcasting Action Strings from your Activities through Intent....
//From any Activity
Intent intent = new Intent(/*"your custom Action String that should match
up with whats set up with the BroadcastReceiver in Service"*/);
sendBroadcast(intent);
6) So once the broadcast is sent your receiver should pick it up then its onReceive() method will be invoked. Therefore you now have a medium for your Activities and Service to communicate through and also the Service will persist even after you close your app until you stop it explicitly with....
//From any Activity
Intent i = new Intent(this, /*MyServiceClassName.class*/);
stopService(i);
7) Stop service when app is stopped....
//In all your activities
#Override
protected void onDestroy() {
Intent i = new Intent(this, /*MyServiceClassName.class*/);
stopService(i);
super.onDestroy();
}
8) First you'd need to put a killcode intent action String in your Service as demonstrated in points 2 and 3 then put this code in your app's Activity onPause() methods....
#Override
protected void onPause() {
PendingIntent pintent = PendingIntent.getBroadcast( this, 0, new Intent(/*"Action String to stop Service"*/), 0 );
AlarmManager manager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
// set alarm to fire 10mins (1000*60*10) from now (SystemClock.elapsedRealtime())
manager.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000*60*10, pintent );
super.onPause();
}
And this in your app's Activity onResume() methods....
#Override
protected void onResume() {
PendingIntent pintent = PendingIntent.getBroadcast( this, 0, new Intent(/*"Action String to stop Service"*/), 0 );
AlarmManager manager = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE ));
manager.cancel(pintent);
super.onResume();
}
i have created one service by extending Service in android and i am sending Message to service using Messenger and Handler.
But the issue (which is a common behavior though) is whenever i have to send message to Service i have to bind it and when i go out of activity i have to unbind it which eventually destroys the service itself.
i can keep running service in background by fringing startService method but is there any way to send Messages to service without using bind as i don't want to destroy the service when i go out of activity.
LocalBroadcastManager is a great way to send messages/data,
In your service class create a private broadcastreciever and string for the intent action name:
public static String MSERVICEBROADCASTRECEIVERACTION ="whatevs";
private BroadcastReceiver mServiceBroadcastReceiver= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("foo","onReceive called");
Log.d("foo","extra = " + intent.getStringExtra("foo")); // should print out " extra = bar"
}
};
And register it in your onCreate
#Override
public void onCreate() {
// your other code...
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceBroadcastReceiver, new IntentFilter(ServiceClassName.MSERVICEBROADCASTRECEIVERACTION));
}
And De-register it in onDestroy()
#Override
public void onDestroy() {
// your other code...
LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceBroadcastReceiver);
}
As for sending messages to it, from an activity or fragment:
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
Intent intent = new Intent(ServiceClassName.MSERVICEBROADCASTRECEIVERACTION);
// add some data
intent.putExtra("foo","bar");
lbm.sendBroadcast(intent);
HTHs you send data without needing to bind!
Unbind Service will not destroy the service. it will disconnect the service connection between the activity and service
Make sure you return START_STICKY to keep your service running
#Override
public int onStartCommand(Intent intent, int flag, int startId)
{
return START_STICKY;
}
Also make sure your running the service as foreground
using notification to keep running the service after the application is removed from stack.
startForeground(1000,mBuilder.build()); // mBuilder - notification builder
I am writing an alarm code and using a broadcast receiver. I am able to receive the broadcast receiver. but now I want to come back to the calling activity and update the UI of my activity. I am not able to this.
I used the following code in my activity but it is never executing that code.
private BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "I am back!!", Toast.LENGTH_LONG).show();
}
};
#Override
protected void onPause()
{
super.onPause();
unregisterReceiver(myBroadcastReceiver);
}
#Override
protected void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter("com.test.Main");
registerReceiver(myBroadcastReceiver, intentFilter);
}
in the manifest file I have included the following, here gotAlarm is the broadcast receiver file
<receiver android:name=".gotAlarm"
android:enabled="true">
</receiver>
gotAlarm file is one which gets called from the pending intent of the alarm set
public class gotAlarm extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "Wake Up!!", Toast.LENGTH_LONG).show();
}
}
May be I am missing something very basic.
please help.
Two things:
If you dynamically register the receiver via Context.registerReceiver() then you won't receive broadcasts when Activity is paused (or stopped or not-running). If you need to receive broadcasts even when Activity is paused then create a top-level BroadcastReceiver class (as opposed to your inner class) and use <receiver> to register it.
BroadcastReceiver lifecycle docs state that BroadcastReceiver object is alive only during processing of onReceive(). You can not do any async tasks like showing dialogs, etc.. In your case (Activities might not be running and you receive a broadcast) you should use NotificationManager to notify user something happened.
I have dropped this way and I am starting a new activity on receiving broadcast. And I am sending information data from calling activity to broadcast and from broadcast to next activity. This has served the purpose.
Did you register your BroadcastReceiver (you can do this in the 'onResume'-method of your Activity)? Also, you should unregister your BroadcastReceiver in the 'onPause'-method.
Maybe it's easy, but I couldn't really figure this out right so far... I got a BroadcastReceiver waiting to get triggered by the AlarmMangager - this works fine.
Now: because the event, if it occurs, needs to refresh some elements on screen of the main Activity, I would like to send an Intent from that background BroadcastReceiver to my Activity - but only if it is currently in the foreground, aka active.
If it is not running or not visible, I don't care - and the last thing I want to do is start the Activity by my intent! I handle repainting of the views in my onResume() method, so I don't care at all.
Any hints on how to do that?
Thanks!
EDIT: my BroadcastReceiver is waiting for alarms that must be notified to the user. So, it must be there and declared in the manifest. The problem is: it will have to decide whether the mentioned Activity is currently up in front or not.
I believe that you're familiar with AlarmManager now (creating a new Alarm, register a receiver...) so I will not talk about that. Just give you a solution for your question.
Instead of registering a BroadcastReceiver in a class file and in manifest, you only create a new BroadcastReceiver in your activity, and then, register it in onResume method, and unregister it in onPause method, sth like this in your activity:
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do something
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction("your alarm action");
...
}
#Override
protected void onResume() {
registerReceiver(mIntentReceiver, mIntentFilter);
...
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(mIntentReceiver);
...
super.onPause();
}
The receiver will only receive the alarm intent when your activity is in foreground :)
(Sorry if my English is not clear)
So this is almost Bino's answer, but: instead of moving the receiver into the activity, use two receivers, with different Intents. The first one is your original alarm Intent, with a receiver registered in the manifest as you already have, and then that receiver sends a second broadcast intent, which is handled by a receiver registered by the activity as Bino says.
I've done this in my own timer project, on github. Here are the alarm receiver and the requery receiver. Hope that helps.