Is onReceive() method of BroadcastReceiver thread safe or I need to implement synchronization on my own?
If I have any class level variable which is being used inside the onReceive() method, and the onReceive() method is called multiple times very quickly, would it cause an issue?
public class MyBroadCastReceiver extends BroadcastReceiver {
boolean isFirstTrigger = true;
#Override
public void onReceive(Context context, Intent arg1) {
if(isFirstTrigger)
{
//Do something time consuming
isFirstTrigger = false;
}
}
Is onReceive() method of BroadcastReceiver thread safe or I need to implement synchronization on my own?
It will only ever be called on the main application thread. Hence, it is thread-safe with respect to anything else running on the main application thread.
If I have any class level variable which is being used inside the onReceive() method, and the onReceive() method is called multiple times very quickly, would it cause an issue?
If the BroadcastReceiver is registered in the manifest, a new instance is created for each broadcast. This is why you do not normally see data members on a BroadcastReceiver.
Related
I'm using FCM to get Messages and a receiver to broad cast messages to my receiver
receiver code:
public class MessageReceiver extends BroadcastReceiver {
private FCMInterface listener;
public MessageReceiver(FCMInterface listener){
this.listener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
}
}
I'm using an interface to connect my receiver to activity(activity implements the FCMInterface)
question is what happens if activity onDestroy calls and after that i call a function of my interface?
The method implemented in the class get called even after the onDestroy() method got called.
But you can no longer access the activity context or anything related to UI.
While setting up the broadcast receiver you should register and unregister on start() and stop() life cycle callbacks. failing to do so will give you memory leak exceptions.
In good android programming practices, you would normally try to avoid situations where you hold the references of objects which are related to the activity context after the onDestroy() has been called.
I think you should send intent to your activity (and set your activity singleTop or singleTask or SingleIntance if you need) instead of interface.
I had setup AlarmManager in my MainActivity class.
A class called AlarmReceiver gets fired up for every set interval of time.
I have to perform an operation when that class is fired up. That code is in in another class Parsing.java
Now in AlarmReceiver.java, I'm doing this :
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Parsing obj = new Parsing(context);
obj.execute();
}
}
I cannot write the code directly in AlarmReceiver.java, because AlarmReceiver.java is already extending BroadcastReceiverand my code which is Parsing.java is extending another class.
So, I'm creating an object for Parsing class and calling that method.
Is my approach correct?
I'll furnish further information in case needed.
Please let me know if my approach is correct?
Thanks in advance!
EDIT:
Parsing.java
public class Parsing extends AsyncTask<Void, Void, Void> {
//some code
}
Starting an AsyncTask from a BroadcastReceiver is wrong for two reasons:
1. The thread on which onReceive() runs is terminated after the method returns, effectively ending any long-running task which may have been started from there. To quote the official docs:
A BroadcastReceiver object is only valid for the duration of the
call to onReceive(Context, Intent). Once your code returns from this
function, the system considers the object to be finished and no longer
active ..... anything that requires asynchronous operation is not
available, because you will need to return from the function to handle
the asynchronous operation, but at that point the BroadcastReceiver
is no longer active and thus the system is free to kill its process
before the asynchronous operation completes.
2. The Context instance that onReceive() provides is not the same as
the Context of an Activity or Service, i.e. Activity.this or
Service.this. You need that proper Context for performing many of
the common useful operations that we usually do from an Activity or
Service. So, for example, the correct way to start a Service in
onReceive() is:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context.getApplicationContext(), ParsingService.class);
context.getApplicationContext().startService(i);
}
and not
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, ParsingService.class);
context.startService(i);
}
I don't know how you wrote your Parsing.java, it looks fine but remember this
This method is always called within the main thread of its process, unless you explicitly asked for it to be scheduled on a different thread using registerReceiver. When it runs on the main thread you should never perform long-running operations in it (there is a timeout of 10 seconds that the system allows before considering the receiver to be blocked and a candidate to be killed). You cannot launch a popup dialog in your implementation of onReceive()
To me, i think it's a better way to handle this is calling another service inside onReceive method, like this
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, ParsingService.class);
context.startService(i);
}
I have a dynamic broadcast receiver registered in a service and my service is doing some heavy sdcard read/write operation in a while(somecondition) loop.
When a broadcast is sent from my another Application (which is in other process) is not received by my broadcast receiver.
This same broadcast is received when it is not executing while loop.
I also tried to put end of loop with Thread.Sleep(100) just to give some time for broadcast receiver to get executed but it is not working.
Any help regarding this will help me a lot.
-Thanks & regards,
Manju
Code below for registering BxRx:
this.registerReceiver(myReceiver, new IntentFilter(ACTIVITY_NAME));
code below for sending broadcast:
Intent intnt = new Intent(ACTIVITY_NAME);
intnt.putExtra("STOP_ALL_TESTING", true);
Log.d(TAG,"Sending BX STOP_ALL_TESTING");
myActivity.this.sendBroadcast(intnt);
code below for while loop:
while(somecondition){
:
:
:
Thred.sleep(100);
}
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Received intent: "+intent.getAction());
boolean flag = intent.getBooleanExtra("STOP_ALL_TESTING", false);
Log.d(TAG,"Flag set to: "+flag);
if((boolean)intent.getBooleanExtra("STOP_ALL_TESTING",false)){
Log.d(TAG,"Broadcast received to STOP_ALL_TESTING");
Log.d(TAG,"Bx Rx, setting flag to stop testing as requested by user");
synchronized(this){
bStopTesting=true;
}
}
}
Please paste your complete code.
It looks like your problem is that you have an endless loop in service's onStartCommand method. Both onStartCommand and onReceive are executed on the same thread and only one after another. Applications main thread is a Looper thread, which handles events in a sequential manner. Basically, if you have an endless operation in the service, you will block the whole main thread, which includes all the GUI, services and Broadcast receivers. Calling Thread.sleep() won't help, because the method does not return. To avoid this, you can use IntentService http://developer.android.com/reference/android/app/IntentService.htmlclass, which will handle intents on another thread.
public class HeavyService extends IntentService {
public HeavyService() {
super("HeavyService");
}
#Override
public void onCreate() {
super.onCreate();
//do your initialization
}
#Override
protected void onHandleIntent(Intent intent) {
//this will be executed on a separate thread. Put your heavy load here. This is
//similar to onStartCommand of a normal service
}
}
I have a BroadcastReceiver registered in the UI thread that grabs some information from the Bundle in its onReceive method. I need these values before I proceed in my main thread.
Is there any way to wait for the onReceive to finish before trying to use those values? I am running into timing issues where onReceive sets the values AFTER I try to use them. Having the thread sleep doesn't work, since they're on the same thread.
Would it make sense to register the receiver in an AsyncTask, and call wait() on the main thread, then have onReceive notify() once it completes?
String a = "hi";
IntentFilter filter = new IntentFilter();
filter.addAction(MY_CUSTOM_INTENT);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Set the variable values here
a = "bye";
}
};
getApplicationContext().registerReceiver(receiver, filter);
// Get the values, I am getting a = "hi" here because the onReceive code has
// not been reached yet
// How can I guarantee that a = "bye" from this method?
getA();
where method is something like
String getA() {
return a;
}
You seem to be over-complicating things. It's hard to know what you're really after based on the example code, but the code that comes after registerReceiver() should just do whatever else it needs to do and then return, without waiting for or hoping for the Broadcast to have been received. onReceive() should include whatever code you want to have executed at that point (which may well just be a method call, e.g. updateA("bye").
Well, if your going to block the main thread either way, might as well do it elegantly.. Register the receiver with the AsyncTask, and use a Dialog to let the user know what you are doing or that you are loading something.
I find that when a BroadcastReceiver starts a Service in onReceive() method, the return of onReceive() will happen before the onCreate() of the Service being invoked. Why does this happen in this order?
The example code is below: BroradcastReceiver's onReceive() method:
public void onReceive(Context context, Intent intent) {
Log.i("=====Receiver=======","===== onReceive starts===="); // (1)
intent.setClass(context, AService.class);
context.startService(intent);
Log.i("=====Receiver=======","===== onReceive ends===="); // (2)
}
Service's onCreate() method:
public void onCreate(){
Log.i("=======Service========", "========OnCreate()=== "); //(3)
// some logic here
}
The log order is (1)(2)(3),not (1)(3)(2).
Could anybody help explain it?
The service has its own thread, so I would guess it doesn't get to run until the thread executing onReceive yields. It could also be that startService posts an intent, but again it doesn't get handled until onReceive returns. I don't know the actual implementation, but I do know that startService is an asynchronous call, so you shouldn't be depending on the order of execution rrlated to onReceive.