I have an android service that I need to stop and restart. In the service's onDestroy(), I have some clean up code that may take a while to execute.
Is there away to notify the application that's using the service that it's finish executing onDestroy()? Or something the application can do to check if onDestroy() has finish its execution?
Yes, use broadcast in onDestroy() method!
Intent intent = new Intent( "Service_destroyed" );
// You can also include some extra data.
intent.putExtra("message", "Service is destroyed!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
That will notify the other activities. Be sure to register the broadcast first in the activities and unregister when not needed anymore.
Register:
LocalBroadcastManager.getInstance(this).registerReceiver(mServiceDestroyedReceiver, new IntentFilter( "Service_destroyed" ));
Here is the method to catch the broadcast:
private BroadcastReceiver mServiceDestroyedReceiver= new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("message");
Log.d(TAG, "Service is destroyed message: " + message);
}
};
Unregister broadcast receiver:
LocalBroadcastManager.getInstance(this).unregisterReceiver( mServiceDestroyedReceiver);
Related
I'm trying to receive broadcasts from a service with 2 different receivers. One receiver update's a view so I register it in the activity's onResume method.
When the app is not in the foreground I use the other receiver so I can show a system notification when the background service completes.
The code below is how I'm registering my receivers:
#Override
protected void onPause() {
// unregister local
unregisterReceiver(localReceiver);
// register remote
registerReceiver(remoteReceiver, filter);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
// remove remote receiver
// since remote is only registered in onPause it won't be registered during the first onResume call
// so we want to ignore any exceptions
try {
unregisterReceiver(remoteReceiver);
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, "No receiver registered, could be first time");
}
// add local receiver
registerReceiver(localReceiver, filter);
Log.i(LOG_TAG, "resumed. should be registered");
}
The two receiver's are instantiated like this at the top of the Activity class:
BroadcastReceiver localReceiver = new BroadcastReceiver() { ... };
WaitTimeReceiver remoteReceiver = new WaitTimeReceiver();
The Service makes the intent as:
broadcastIntent = new Intent(Support.SERVICE_BR);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
// later on sends using
sendBroadcast(broadcastIntent);
The Filter in the Activity is made to match:
filter.addAction(Support.SERVICE_BR);
filter.addCategory(Intent.CATEGORY_DEFAULT);
Everything above is working the pause resume functionality works as expected, but my question is why the LocalBroadcastManager was not?
Using LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this) and then calling lbm.registerReceiver(localReceiver) was not receiving any of my broadcasts for either.
Why wasn't the LocalBroadcastManager receiving any of my broadcasts?
BroadcastReceivers registered with LocalBroadcastManager can only receive broadcasts sent with LocalBroadcastManager. Broadcasts sent with an Activity's or Service's sendBroadcast() method cannot be received by LocalBroadcastManager Receivers.
Use the LocalBroadcastManager#sendBroadcast() method instead. For example:
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
In my App, there is a condition which check every day and if it gets true then I want my App get close in between the run like a crash and stack also gets clear .
I have try and tested many solutions but didn't find the one that works the way i wanted .
My BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
PreferenceForApp prefs = new PreferenceForApp(context);
Bundle bundle = intent.getExtras();
if (bundle!=null){
if(bundle.containsKey("exception")) {
// String e = bundle.getString("exception")
if(bundle.get("exception").toString().equalsIgnoreCase("http request failed with error_msg No Match Found")) {
prefs.setIsDeviceValidated(false);
prefs.setIsLogIn(false);
Log.i("Time", "Exception Occur");
Intent CSPIntent=new Intent(context,CSPLoginActivity.class);
CSPIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
CSPIntent.putExtra("close_activity", true);
Log.i("Time", "IntentExit");
context.startActivity(CSPIntent);
}
}
}
}
}
And code to finish in an Activity I am calling from broadcastReceiver:
if (getIntent().getBooleanExtra("close_activity",false)) {
Log.i("Time", "ExitCSPLogin");
this.finish();
}
This code is not closing App in between the run.
You need to register BroadcastReceiver in your activity and send broadcast to BroadcastReceiver when you want to close application.
In your Activity try this:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.package.ACTION_CLOSE");;
BroadcastReceiver Receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(Receiver, intentFilter);
in onDestroy() method of you Activity unregister BroadcastReceiver:
#Override
protected void onDestroy() {
unregisterReceiver(Receiver);
super.onDestroy();
}
Now when you want close application send broadcast to BroadcastReceiver:
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.package.ACTION_CLOSE");
sendBroadcast(broadcastIntent);
Hope this helps!
you have to check below condition in your app's mainActivity's onCreate method every time when user enter in your app. or in onResume if you want to to close your app immediately
if (!prefs.getIsDeviceValidated()) {
Log.i("Time", "ExitCSPLogin");
this.finish();
}
i assume you have more then one activity in your app, so insted of check above flag in every activity we 'll put it in main activity. allow user to use your app until he/she come at mainActivity
Note: create Broadcast Receiver for your App(add in manifest), not for specific activity
I have a service that get data from an other application.
When I get date I send message to broadCast in order to refresh the UI.
The onReceive method is called many times and data displayed multiple times.
this is my code:
DataService.java
if(sizeLat == 1) {
sendMessage("Alerte1;");
}
else {
sendMessage("Alerte2;");
}
private void sendMessage(String message) {
Log.w("","==> send message");
Intent intent = new Intent("my-event");
// add data
intent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
MainActivity.java
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("","Onreceiver");
String message = intent.getStringExtra("message");
if(message.equals("Alerte1")){
parentItems.add(message);
adapter.notifyDataSetChanged();
}}};
#Override
protected void onResume() {
Log.d(TAG, "On Resume");
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
How can I resolve the problem ?
Put broadcast register line in onCreate and unregister it in onDestroy() method. The line which you have to move from onResume() to onCreate is:-
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
Possibly, you have two instances of the activity living at the same time. Make a breakpoint on the message receiver and check the address of the instance of your activity class and see if they are different each time the onReceive is called.
There are a few reasons why you could have two instances living at the same time, but one of the most common is leaking context within the activity.
More on this topic.
I fixed same problem by unregister BroadcastReceiver in onPause method
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver,new IntentFilter("my-event")));
Register it in OnResume Method
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));}
1) I have an Activity. This Activity starts a service, which in turn creates and registers a BroadcastReceiver.
2) I have an Activity. This Activity creates and registers a BroadcastReceiver.
When does BroadcastReceiver's life end in each of the above cases? In other words - when it gets destroyed and won't listen to broadcasts anymore?
Declare broadcast receiver in manifest to achieve independent life cycle for it.
http://developer.android.com/reference/android/content/BroadcastReceiver.html
Only onReceive() method is called in BroadcastReciver's life cycle.
A BroadcastReciever life cycle ends (ie stop receiving broadcast) when you unregister it. usually you would do this in the onPause/onStop method. but it's up to you technically.
Example:
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
I have an intent that gets sent under a certain condition. The logs prove it is only sent ONCE, but the receiver is receiving it multiple times milliseconds apart.
10-01 10:09:59.201: I/System.out(13543): SENDER CHECKPOINT
10-01 10:09:59.211: I/System.out(13543): RECEIVER CHECKPOINT
10-01 10:09:59.291: I/System.out(13543): RECEIVER CHECKPOINT
I have confirmed that there is only ONE registration of the Broadcast Receiver and only ONE action filter used with the registered BR. It is only used in a single activity where a service running in another thread broadcasts the intent. Again, the logs substantiate the ONE broadcast and multiple receipts. What's more, the extras are null in the echo receipt.
How can this be? Is it possible the OS is echoing it?
Code that sends the broadcast:
private void sendBroadcast(boolean status, String message, String action){
System.out.println("SENDER CHECKPOINT");
Intent intent = new Intent(action);
Bundle bundle = new Bundle();
bundle.putBoolean("status", status);
bundle.putString("message", message);
intent.putExtras(bundle);
sendBroadcast(intent);
}
Code that receives the broadcast:
private class displayUpdate extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("RECEIVER CHECKPOINT");
};
}
Registration:
#Override
public void onResume() {
super.onResume();
try {
// just in case onResume is called w/o a pause
try{activity.unregisterReceiver(displayReceiver);}catch(Exception e){}
filterRefreshUI = new IntentFilter(REFRESH_UI);
activity.registerReceiver(displayReceiver, filterRefreshUI);
} catch (Exception e) {
e.printStackTrace();
}
}
Unregistration:
#Override
public void onPause() {
super.onPause();
try{unregisterReceiver(displayReceiver);}catch(Exception e){}
}
REALLY IT'S THAT SIMPLE! Yet the receiver fires TWICE!
In case you were wondering - Registration/Unregistration are handled in the onPause/onResume to prevent leaking memory if the App is killed by the OS.