On receiving a certain event in my Android service, I want to terminate the app from within the service. I know I can call finish in an activity to end it.
Also I understand that service will call stopSelf() on itself to end itself. But I need to terminate the entire app including any particular activity of the app that was visible at that time.
Any ideas?
Try this:
Process.killProcess(Process.myPid());
You can create an BaseActivity with BroadcastReceiver to close all Activities by registering it in onCreate() of BaseActivity and extending all your Activities with BaseActivity.
public static final String EXIT_APP_ACTION = "EXIT_APP_ACTION";
BroadcastReceiver ExitAppBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
Register it in onCreate() for the BaseActivity in your Application using,
registerReceiver(ExitAppBroadcastReceiver, new IntentFilter(EXIT_APP_ACTION));
Then you can fire this BroadcastReceiver from your Service using the Context to close all Activites including Service by calling stofSelf(),
stopSelf()
context.sendBroadcast(new Intent(BaseActivity.EXIT_APP_ACTION));
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" />
I had to implement a feature to this app which consists of an Activity and a Service working on the background (it implements Service, not IntentService).
I went through a few tutorials on the Internet that are supposed to work, and they all use LocalBroadcastManager, which by the way is the recommended by Android:
If you don't need to send broadcasts across applications, consider
using this class with LocalBroadcastManager instead of the more
general facilities described below.
I literally lost a day to find out the problem why it wouldn't work for me: it only works if I use Context.sendBroadcast(). and Context.registerReceiver() instead of the LocalBroadcastManager methods.
Now my app is working, but I feel I am going against the best practices, and I don't know why.
Any ideas why it could be happening?
EDIT:
After I wrote this question I went further on the problem. LocalBroadcastManager works through a Singleton, as we should call LocalBroadcastManager.getInstance(this).method(). I logged both instances (in the Activity and in the Service) and they have different memory addresses.
Now I came to another question, shouldn't a Service have the same Context as the Activity that called it? From this article a Service runs on the Main Thread, hence I'd think the Context would be
the same.
Any thoughts on that? (sorry for the long post)
Code samples:
MyService
public class MyService extends Service {
...
// When an event is triggered, sends a broadcast
Intent myIntent = new Intent(MainActivity.MY_INTENT);
myIntent.putExtra("myMsg","msg");
sendBroadcast(myIntent);
// Previously I was trying:
// LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(myIntent);
}
MyActivity
public class MainActivity {
...
private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("onReceive", "received!");
// TODO something
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(messageReceiver, new IntentFilter(MY_INTENT));
// Previously I was trying:
// LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(messageReceiver, new IntentFilter(MY_INTENT));
}
}
I've never used LocalBroadcastManager, but it sounds like you have to register your receiver on there (i.e. lbm.registerReceiver(...), not mycontext.registerReceiver(...)). Are you doing that?
Now I came to another question, shouldn't a Service have the same Context as the Activity that called it? From this article a Service runs on the Main Thread, hence I'd think the Context would be the same.
The Context class is not related to threads. In fact, both Service and Activity are (indirect) subclasses of Context -- so they're their own Contexts! That's why you can use "this" as a Context.
But regardless of which context you send into LocalBroadcastManager.getInstance(), you should be getting the exact same LBM instance out. I can't think of any reason that you wouldn't -- except if you're running the Activity and Service in different processes?
Declaration:
private BroadcastReceiver receiver;
Initialization:
receiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
//todo
}
};
Registration:
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, new IntentFilter("RECEIVER_FILTER"));
context can be any type of Context, you can use the application context.
Unregister:
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
Broadcast:
Intent intent = new Intent("RECEIVER_FILTER");
intent.putExtra("EXTRA", someExtra);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
check out if your Service and Activity are run in different process, LocalBroadcastManager can't apply in different process.(you should see it in AndroidManifest.xml file)
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
I want to use BroadcastReceiver in my application as AsyncTask result indicator in different Activities and therefore AsyncTasks too. I think my approach is little wrong or I missed something.
Here what I'm doing: Firstly, during onCreate I registered my receiver as a BroadcastReceiver using the registerReceiver method. My receiver looks like:
protected BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String msg_for_me = intent.getStringExtra("some_msg");
Log.i("Tutorial", msg_for_me);
}
}
In my application, I've A and B activities. Each have different receivers which getting messages from different tasks. By the way, I must clarify that, A activity starting B activity.
I'm using receiver which in activity A, then activity A starting B using the startActivity. In activity B, I'm executing an AsyncTask and on onPostExecute I'm sending a broadcast with B activity's context. But somehow still A activity's receiver getting message. Both receivers have the same content but have different names.
So here are my issues:
Should I unregisterReceiver when I started new activity on onPause method?
Is BroadcastReceiver that how I'm using, only for one call? Should I register again and again whenever I send any message?
I'm pretty sure I didn't define any receiver to Manifest. I suppose this is what I'm doing wrong. If this is well, how can I use IntentFilter while sending broadcast?
Please let me know if there is uncertain question. Any clues about BroadcastReceiver would be great and appriciated.
Yes, you should unregister broadcast receiver on activity pause. It
is the potential leak.
No broadcast receivers are not for one call.
They are called everytime the broadcast is done for the registered
intents.
You can register the receiver for particular intent on
OnResume like this,
mContext.registerReceiver(iReceiver, new android.content.IntentFilter("android.intent.action.BATTERY_CHANGED"));
Where iReceiver is ,
iReceiver = new IntentReceiver();
private class IntentReceiver extends BroadcastReceiver {
private final String LOG_TAG="IntentReceiver";
#Override
public void onReceive(Context arg0, Intent intent) {
}
}
and unregister the same on OnPause
mContext.unregisterReceiver(iReceiver);
I have two applications. One is a receiver and its starting my application. It works fine. Now i want destroy my application from the receiver itself. Is that possible ? Please note that these are my own application
It is possible but the activity has to finish itself using the finish()-method.
You can register an activity to a receiver using registerReceiver(..) and handle your logic in your activity. Don't forget to unregisterReceiver(...) inside the OnDestroy.
Example:
BroadcastReceiver mReceiver;
#Overrride
public void onCreate(Bundle savedInstanceState){
IntentFilter filter = new IntentFilter();
filter.addAction(...);
mReceiver= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// implement logic
finish();
}
}
registerReceiver(mReceiver, filter);
}
you cant directly control the lifecycle of one activity from another actvity
alternates to this could be :
you can set a timer in the new activity, if you want to end it after a certain amount of time, and call finish()' inrun()`
you can finish() the new activity on some events with EventListeners