Android - get a reference to a BroadcastReceiver defined in Manifest - android

Is there any way how to get a reference for a BroadcastReceiver defined in Manifest.xml from code?
In my case, we are using a BroadcastReceiver that needs to be included in the Manifest.xml. However it has functionality I would like to reuse from within our code. So instead of creating another similar BroadcastReceiver and instantiating it from the code I would like to obtain a reference to the existing one.
Additional information:
My goal is to subscribe to an event on my BroadcastReceiver from my activity - an event that I would like to reuse - instead of creating another instance of this receiver in my activity I would like to obtain a reference to the existing one.

When registering a BroadcastReceiver in the manifest, you're registering the class, not an instance of it. Each time a broadcast occurs that your <receiver> needs handle, a new instance is created to do so, so you can't really get a reference to one as you're describing.
It's perfectly fine to dynamically instantiate and register an instance of a Receiver class that you've also statically registered in the manifest. I would note, though, that if the statically registered class is going to be run anyway - that is, if it's going to handle the same broadcasts as the dynamically registered one - you might consider just notifying your Activity from the Receiver class - e.g., with LocalBroadcastManager, another event bus implementation, etc. - instead of essentially duplicating Receivers.

There's no need to 'obtain a reference' to BroadcastReceiver which is already registered.
Just send Intent which can be handled by that BroadcastReceiver to trigger its action from any point of the code where you have a Context.
context.sendBroadcast(intent);
If you want to call 'pure logic' without calling BroadcastReceiver you have to extract logic from it to some POJO class and call that class directly omitting BroadcastReceiver.
class LocationReceiver extends BroadcastReceiver {
private SomeAction action;
public LocationReceiver(){
action = new SomeAction();
}
#Override
public void onReceive(Context context, Intent intent) {
action.execute();
}
};
BroadcastReceiver can simply call execute() but it doesn't know anything about how it works.
You can reuse SomeAction anywhere in your code without having a knowledge about BroadcastReceiver at all.
Try to avoid putting a logic inside Android classes.
It's better to have logic in POJO Java classes because it helps to keep SRP principle alive and makes testing easier.

Related

Drawbacks in registering receivers in both the activity and service?

The scenario is like this: I have an activity and a service. There are a few things that need to be sent between both:
the activity can query the service to see if running
the activity can query the service for variable value
the activity can ask the service to perform action (run a method of it)
the service can send response to the activity on action
the service can respond back to activity on activity call
Since this looks more as a two-way communication, I am thinking of using LocalBroadcastManager and have something like:
public class MyActivity extents Activity{
private void receiver = new BroadcastReceiver(){
onReceive(){
//Handle Message from Service
}
}
onResume -> LocalBroadcastManager.registerReceiver(receiver);
onPause -> LocalBroadcastManager.unregisterReceiver();
}
and for service
public class MyService extents Service{
private void receiver = new BroadcastReceiver(){
onReceive(){
//Handle Message from Activity
}
}
onStart-> LocalBroadcastManager.registerReceiver(receiver);
onDestroy-> LocalBroadcastManager.unregisterReceiver();
}
This would allow to avoid binding or other methods of communication between app components but in the same time allows both to sent intents and listen for observers. Are there any drawbacks on this method?
There shouldn't be.
This is the recommended way of cross-component communication within an Android app. You're doing exactly what Google recommends, with local broadcasts instead of global broadcasts.
In a comment, you mentioned that binding a Service is usually what to do for Activity->Service communication. You don't need to use this in most cases. Binding a Service is kind of annoying, since it isn't instant and you need to use a listener to store a reference to the Binder. Broadcasts, in comparison, are relatively simple.
Looks like your activity should just bind to the service to get a Binder instance that you can use to access service methods. The service can send local broadcasts that the Activity can observe with Broadcast Receivers. My recent preference is have the service methods return LiveData instances that can be observed instead. LiveData objects are lifecycle aware so any observers will know to clean up after themselves.

reset TextView from two activities in OnReceive method

I have two acitivties and want to reset values in them everyday at 00:00.
Question:
Is there any way to link two activities to onReceive method of broadcastReceiver so I can update activities(TextView and EditText) from onReceive?
Create a BroadcastReceiver class and register it in your manifest. Also pass the instances of your activities to the BroadcastReceiver when you declare it so you can know which one you are clearing/using.
Now make your clearing methods public in both of your activities and call them from your BroadcastReceiver using the instances of each activity.
Check THIS tutorial and THIS one on how to use BroadcastReceiver class.

How do you call a method in an activity from a broadcastreceiver that is registered in manifest without starting the activity with an intent?

I have a extended broadcastreceiver class that listens for bluetooth connection/disconnection. I want it to change a color of some text in my GUIActivity. I don't have it as an inner class on purpose: to keep the GUI code more manageable/modular.
I know of one way to do this: register the receiver dynamically and pass it in the context of the activity. Then do the normal registering/unregistering in onResume and onPause. This solution can be seen at this post
However, I was hoping I could eliminate just a little bit more code by having my receiver registered in the manifest and not worry about registering/unregistering.
I have tried casting the context in the onReceive on the Broadcastreceiver as follows
((SmokinoGUI) context).indicateBTConnection();
This throws an exception saying that context cannot be cast to SmokinoGUI. indicateBTConnection() is a method in the SmoinoGUI activity that does what it says.
So, is there a way to call a method in an activity from a broadcastreceiver that has been registered in the manifest and has not been dynamically instantiated?
So, is there a way to call a method in an activity from a broadcastreceiver that has been registered in the manifest and has not been dynamically instantiated?
There is lot of ways. My favorite is:
Extends Application class and assign that class to your Application name attribute in Manifest.
Add instance of your Activity in that class and create getter and setter to it, that you could reference to in Activity onCreate() .
Get application in your BroadcasetReceiver and call the getter to the Activity.
If all this sound complicated, well, it really not, and it good logic to use in every app. I could add some code for example.

Global Broadcast Receiver (Android)

I have an application with several activities and I want to be notified when the phone goes online (doesn't matter which activity is the user in). I've found a Broadcast Receiver to do it, but I'd like to know if there is a way to declare this BroadcastReceiver only once, I want to avoid having to place the code in each activity (I have more than 20 activities!).
Thank you.
Create a parent abstract class which extends Activity and define the broadcast receiver implementation there. Later, modify your activity classes to extend that parent class.
As in documentation, If we declares the broadcast receiver in manifest file then it automatically runs behind.
Thing is that now you need to handle the onReceive() method of the receiver.
Another way is that you make a separate java class and import wherever you want.

Register BroadcastReceiver to Widget (Difference of Context object)

A have a little confuse the difference between Widget Context and Application Context:
Regarding problem relate with unable to register new BroadcastReceiver via implement source code of Android Widget (Ref.1)
For readability reason, i copy my answer as below:
★Problem by Henry (Ref.1):
I am making a widget that needs a
broadcast receiver, like the one in
com.example.android.apis.appwidget.ExampleBroadcastReceiver.
However, the example defines
Intent.ACTION_TIMEZONE_CHANGED in the
manifest, but there are some that do
not allow this
For example, Intent.ACTION_TIME_TICK
says "You can not receive this through
components declared in manifests, only
by exlicitly registering for it with
Context.registerReceiver(). "
So I removed the manifest declarations
and tried replacing the
AppWidgetProvider.onEnabled function
that was in the example with a call
like the following:
context.registerReceiver(myReceiver,
new
IntentFilter(Intent.ACTION_TIME_TICK));
(where "myReceiver" is an instance of
the receiver I want.) However, when I
try to run the code, I get the
following error:
Unable to start
receiver...android.content.ReceiverCallNotAllowedException:
IntentReceiver components are not
allowed to register to receive intents
★Our analysis this issue and solution for this problem (Ref.1)
This is result after investigate this
problem, i was handler successful this
issue. So i collect as report to share
with android developer. Hope it help
Here is result:
❶ISSUE:*
Regarding limited from Widget, when try to register
BroadcastReceiver via explicit source
code: (No effect when register
BroadcastReceiver via Manifest.xml)
❷EXAMPLE: *
BroadcastReceiver: ACTION_TIME_TICK message is one
example: As docs from Android had
point out: "You can not receive this
through components declared in
manifests, only by exlicitly
registering for it with
Context.registerReceiver()." (Ref.1)
❸PREVIOUS SOLUTION:* Code Snippet: context.registerReceiver(this,
intentName); (1)
❹ERROR when used 3★ solution* When implement follow (1), it though
exception:
android.content.ReceiverCallNotAllowedException:
IntentReceiver components are not
allowed to register to receive intents
★Good news for anyone who need to
register BroadcastReceiver in Widget
:) we CAN register successful
BroadcastReceiver
❺OUR SOLUTION:* But, We can fixed this by used application context
instead of Widget context(*) Code
Snippet:
context.getApplicationContext.registerReceiver(this,
intentName);
❻REFERENCE:* http://developer.android.com/reference/android/content/Intent.html#AC...
Regarding
❼TARGET ENVIRONEMNT:* SDK 2.3, both on Emulator and NexusOne 2.3, If
anyone success with this solution
please update our report
❽NOTES* May be difference between Context object of widget and
application, but i still don't known
exactly cause of this problem.
Please let me known if your have
better solution or explain more
clearly
Also i had solver this problem, but i
still don't known exactly cause of
this problem.
Please let me known if your have
better solution or explain more
clearly
★CONCLUTION:
● NG: When use Widget context to register BroadcastReceiver
context.registerReceiver(this, intentName);
-> it thought exception:
Unable to start receiver...android.content.ReceiverCallNotAllowedException: IntentReceiver components are not allowed to register to receive intents
● OK: When use Application context everything working fine:
ontext.getApplicationContext.registerReceiver(this, intentName);
★QUESTION:
Also our solution can solver problem: "unable to register new broadcast message via implement source code of Android widget".
But i still concern two Qestion:
Question❶: The difference between Widget Context and Application Context and other Context object (Activity Context)'
Question❷: Because context object was use usually so when to use Application context and when to use other Context.
For ❷ i had found explain relate with memory leak (Ref. 2), but i think it may not enough (Ref.2)
So if your have answer please let me known, any answer appreciated.
Thanks
★Referecens:
(1) http://groups.google.com/group/android-developers/browse_thread/thread/790da1a655f4a227/0b8d6aad1dc2d371?hl=en&lnk=gst&q=Broadcast+Receiver+From+Widget#0b8d6aad1dc2d371
(2) http://developer.android.com/resources/articles/avoiding-memory-leaks.html
This question is over a year old and is definitely long and complicated and the English language is difficult to understand. However, it still probably deserves some kind of answer.
If I understand, you are basically asking for the difference between the different Android Context objects. The main difference is scope or lifetime.
The application's Context (that you can get with Activity.getApplicationContext() or Context.getApplicationContext() has a lifetime of your entire application. The application Context is created when your application (or parts of it) are started. It lives (more or less) forever.
An activity's Context is created when that Activity is created and goes away when that activity is destroyed. If you are doing anything with the UI, you need to do that using the activity's Context so that when the activity is destroyed, those things that are related to that activity are also cleaned up.
There are other Contexts like the one you get in a BroadcastReceiver or an AppWidgetProvider in onReceive(). This Context has a very short lifetime (it is destroyed immediately after the onReceive() method returns). Therefore you can only do limited things with this Context.
You want to register a Receiver to listen for the broadcast Intents you are interested in. You cannot do this with the Context you get in onReceive() because that Context has a short lifetime and the listener has to be linked to something. In this case you can use the application's Context to link the listener to. This works, but you need to realize that you've created some objects that will never go away because they are always active. At least you should make sure that you clean this up when the user deletes your widget from his home screen by removing the listener using unregisterReceiver().
There are a lot of questions/answers on StackOverflow regarding usage of Context. For example, What's the difference between the various methods to get a Context?
Even though David Wesser provided an excellent answer, I think there are still relevant information to be added. So here it goes:
In the end, Context is just a reference to different components of your own app (like resources, package information, etc) and to the operating system outside it. So all different contexts you mentioned are just a reference to the same thing, the only difference is for how long each reference is valid.
In the specific case of AppWidgetProvider, the context you get on its methods is the same context provided by BroadcastReceiver onReceive method. Actually AppWidgetProvider is just a fancy name for a regular BroadcastReceiver which calls specific methods when receiving widget related intents, like ACTION_APPWIDGET_UPDATE.
The problem with your code is that AppWidgetProvider has a very short lifecycle: every time a widget broadcast arrives, a new instance of AppWidgetProvider is created just to execute the correspondent method. So when you do this:
context.getApplicationContext.registerReceiver(this, intentName);
you are registering a new BroadcastReceiver to your app context every time a widget intent is received. Besides that, when you try to unregister your AppWidgetProvider, you are actually referring to another instance of it, so you will probably get an exception and even if you catch it, there will be a memory leak on your app.
So if you need to programmatically add intent filters to a BroadcastReceiver here is my suggestion:
1)Create a different BroadcastReceiver on a long lived context class, like a class that extends Application. Lets call it mMainReceiver.
2)Apply the intent filter programatically on it, and register and unregister it according to your needs.
3)Create a private intent, like MY_ACTION_TIME_TICKER and fires it from your mMainReceiver onReceive method.
4)On your manifest, register a MY_ACTION_TIME_TICKER filter to your AppWidgetProvider receiver.
This way you can have a single BroadcastReceiver acting as a bridge to your AppWidgetProvider, and you can register and unregister it anytime.

Categories

Resources