i have an Activity where inside a method a send a broadcast to a custom receiver located in Activity's Fragment...i would like to set a permission as a second parameter of sendBroadcast so my receiver can receive only specific broadcasts...
Activity's sendBroadcast():
#Override
public void update(Observable observable, Object connectionStatus) {
Log.e(debugTag, connectionStatus+"");
intent = new Intent("networkStateUpdated");
intent.putExtra("connectivityStatus", (int) connectionStatus);
sendBroadcast(intent, "mypermission");
}
initialization of custom Receiver inside Fragment's onActivityCreated
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
connectionStatus = intent.getExtras().getInt("connectivityStatus");
}
};
#Override
public void onResume() {
super.onResume();
getActivity().registerReceiver(broadcastReceiver, new IntentFilter("networkStateUpdated"), "mypermission", null);
}
#Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(broadcastReceiver);
}
setting "mypermission" as second parameter of sendBroadcast is apparently not working..
Use system broadcasts (e.g., sendBroadcast() called on Context) when you need to send messages between processes.
Within a process, using system broadcasts adds IPC overhead and security concerns. Instead, use some sort of in-process event bus. Personally, I use greenrobot's EventBus. LocalBroadcastManager is part of the Android Support libraries. Others prefer Square's Otto or other event bus implementations. These are less expensive in terms of overhead, and they are private to your app, so there are no new security concerns.
Related
I've look at many solutions to other questions with similar issues but I can't figure out what's wrong with my code. I understand that LocalBroadcast is a popular way to do this and I've spent time trying to implement it. At the moment, the receiver isn't declared in my manifest but from what I understand, that's what the register lines are for.
In my activity:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("MyActivity", "onReceive");
String action = intent.getAction();
int current = intent.getIntExtra("test", 0);
Toast.makeText(MyActivity.this, current.toString(), Toast.LENGTH_LONG).show();
}
};
#Override
public void onResume() {
super.onResume();
Log.d("MyActivity", "onResume()");
LocalBroadcastManager.getInstance(MyActivity.this).registerReceiver(
mMessageReceiver, new IntentFilter("currentUpdate"));
}
#Override
protected void onPause() {
Log.d("MyActivity", "onPause()");
LocalBroadcastManager.getInstance(MyActivity.this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
In the service I have a method defined:
private void sendNewBroadcast(Intent intent, int current){
intent.putExtra("test", current);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.d("MyService", "new Broadcast sent from service");
}
and I use it like this elsewhere in the service:
Intent intent = new Intent("currentUpdate");
sendNewBroadcast(intent, 5);
I've debugged and everything seems to be working except for the 'receiving' part. Am I missing something? The service is started in a different activity and is ongoing.
Firstly, the action String on the broadcast Intent needs to match the action set on the IntentFilter you're registering the Receiver with. Originally, they were different, but it was possibly just a typo.
Secondly, LocalBroadcastManager does not work across processes. The Activity and the Service must be running in the same process to be able to use LocalBroadcastManager. If the Service needs to be in a separate process, you'll have to use some other mechanism; e.g., Intents, broadcasts sent and received on a Context, some event bus implementation that supports IPC, etc.
My service:
#Override
public void onCreate() {
if (debug_mode) {Log.i(TAG,"onCreate");}
super.onCreate();
// set receivers
m_filter.addAction("PREPARE_AUDIO");
m_receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (debug_mode) {Log.i(TAG,"broadcast received: " + intent.getAction());}
if (intent.getAction().equals("PREPARE_AUDIO")) {
set_up_audio();
}
}
};
registerReceiver(m_receiver, m_filter);
}
and my activity:
#Override
protected void onStart() {
super.onCreate(savedInstanceState);
if (debug_mode) Log.i(TAG, "onCreate");
setContentView(R.layout.activity_guide);
// start service
startService(new Intent(this, PlayerService.class));
}
#Override
protected void onStart() {
if (debug_mode) {Log.i(TAG,"onStart");}
super.onStart();
// prepare audio
Intent intent = new Intent();
intent.setAction("PREPARE_AUDIO");
sendBroadcast(intent);
}
This won't trigger the BroadcastReceiver in my service. It won't trigger it either if I put the code on onCreate or onResume. It will trigger it, however, if put e.g. on some Listener associated with a Button, or in the activity's onStop callback. Why is that?
Rather than try to send a broadcast right away, just have the service do its setup work in its onCreate() or onStartCommand() method.
Note that using system broadcasts for this is a fairly bad idea, unless your service is in a separate process from your UI. Even then, you need to think through the security, as any app can tell your service what to do, by sending it broadcasts.
If your service and UI will be in the same process, use an in-process event bus (e.g., LocalBroadcastManager, greenrobot's EventBus), not only for improved security, but for better performance.
I'd like to notify my Activity of any Wifi connection changes using the BroadcastReceiver. Since this broadcast is within the application I'm trying to use the more efficient LocalBroadcastManager object.
However no matter what I do, the BroadcastReceiver.onReceive() method will not fire. I may have wired it up incorrectly, or perhaps the WifiManager.NETWORK_STATE_CHANGED_ACTION action I'm listening for cannot be registered against a LocalBroadcastManager? Any help or clarification would be appreciated.
Here's a sample of my Activity class which contains all the logic.
public class MyActivity extends ActionBarActivity {
private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
{
// Do something
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
IntentFilter wifiStatusIntentFilter = new IntentFilter();
wifiStatusIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
wifiStatusIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(wifiReceiver, wifiStatusIntentFilter);
}
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(wifiReceiver);
}
protected void onResume() {
super.onResume();
IntentFilter wifiStatusIntentFilter = new IntentFilter();
wifiStatusIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(wifiReceiver, wifiStatusIntentFilter);
}
}
When I switch the wifi on my mobile on and off, or enter and leave the wifi range, the onReceive() method is never fired.
You can't receive WifiManager.NETWORK_STATE_CHANGED_ACTION with LocalBroadcastManager. LocalBroadcastManager works only within your process.
Helper to register for and send broadcasts of Intents to local objects
within your process. This is has a number of advantages over sending
global broadcasts with sendBroadcast(Intent):
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes
they can exploit.
It is more efficient than sending a global broadcast through the system.
You should use registerReceiver of Context
Since this broadcast is within the application I'm trying to use the more efficient LocalBroadcastManager object.
That only works for broadcasts that you send via LocalBroadcastManager. It does not work for system broadcasts, particularly those sent by other processes.
perhaps the WifiManager.NETWORK_STATE_CHANGED_ACTION action I'm listening for cannot be registered against a LocalBroadcastManager?
Correct.
I have a receiver, it does call details saving task like storing incoming call, outgoing call etc.. all these details goes to sqlite DB. If my activity is not running, then its fine.
Sometime, when my activity is running, i get some incoming call. the receiver runs & stores data to DB. UI wont get refreshed because it never knows about change in DB.
Here i need to manually tell from receiver that, if activity is running refresh screen. How to implement this process in android.
I'm slightly confused in this part
You can use a LocalBroadcastManager to send a local broadcast to your Activity (more efficient and more secure than using a global broadcast):
Intent intent = new Intent(action);
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(context);
mgr.sendBroadcast(intent);
http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
Your Activity would have to register a BroadcastReceiver in onStart and unregister it in onStop:
private BroadcastReceiver mBroadcastReceiver;
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do your thing
}
};
LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this);
mgr.registerReceiver(mBroadcastReceiver, new IntentFilter(action));
in onStop:
mgr.unregisterReceiver(mBroadcastReceiver)
Now that's the official Android way to do it. I most certainly prefer to use an event/message bus like Otto or EventBus (https://github.com/greenrobot/EventBus). You can use those to broadcast messages/events across different components in your app. The advantage is you don't need access to a Context (like you do when using Broadcasts), it's faster and it forces the developer to object oriented programming (since the events are always objects). Once you start using an event bus you'll never look back to local broadcasts and you'll replace many of the sometimes messy observer / listener patterns used across your app.
You can create a BroadcastReceiver inside an activity. Register it in onResume() and unregister it in onPause(). Whenever your other receiver receives a broadcast, send a broadcast to this receiver too. If the activity is running(i.e. on front), the broadcast will be received. Do whatever you want in its onReceive().
Example:
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do stuff
}
};
Also override methods:
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(br);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(br, new IntentFilter("intent_filter"));//Use any string for IntentFilter you like
}
You can update fragments from activiy by creating methods inside fragment and access them from Fragment object inside activity.
I'd like to know what is the best practice/way of programmatically register a broadcast receiver. I want to register specific receivers according to user choice.
As the registration is done through the manifest file, I'm wondering if there's a proper way to achieve this in code.
In your onCreate method you can register a receiver like this:
private BroadcastReceiver receiver;
#Override
public void onCreate(Bundle savedInstanceState){
// your oncreate code should be
IntentFilter filter = new IntentFilter();
filter.addAction("SOME_ACTION");
filter.addAction("SOME_OTHER_ACTION");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do something based on the intent's action
}
};
registerReceiver(receiver, filter);
}
Remember to run this in the onDestroy method:
#Override
protected void onDestroy() {
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
super.onDestroy();
}
One important point that people forget to mention is the life time of the Broadcast Receiver. The difference of programmatically registering it from registering in AndroidManifest.xml is that. In the manifest file, it doesn't depend on application life time. While when programmatically registering it it does depend on the application life time. This means that if you register in AndroidManifest.xml, you can catch the broadcasted intents even when your application is not running.
Edit: The mentioned note is no longer true as of Android 3.1, the Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu (in Manage → Application). https://developer.android.com/about/versions/android-3.1.html
This is an additional security feature as the user can be sure that only the applications he started will receive broadcast intents.
So it can be understood as receivers programmatically registered in Application's onCreate() would have same effect with ones declared in AndroidManifest.xml from Android 3.1 above.
It sounds like you want to control whether components published in your manifest are active, not dynamically register a receiver (via Context.registerReceiver()) while running.
If so, you can use PackageManager.setComponentEnabledSetting() to control whether these components are active:
http://developer.android.com/reference/android/content/pm/PackageManager.html#setComponentEnabledSetting(android.content.ComponentName, int, int)
Note if you are only interested in receiving a broadcast while you are running, it is better to use registerReceiver(). A receiver component is primarily useful for when you need to make sure your app is launched every time the broadcast is sent.
Define a broadcast receiver anywhere in Activity/Fragment like this:
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG," onRecieve"); //do something with intent
}
};
Define IntentFilter in onCreate()
mIntentFilter=new IntentFilter("action_name");
Now register the BroadcastReciever in onResume() and Unregister it in onPause() [because there is no use of broadcast if the activity is paused].
#Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
#Override
protected void onPause() {
if(mReceiver != null) {
unregisterReceiver(mReceiver);
mReceiver = null;
}
super.onPause();
}
For detail tutorial, have a look at broadcast receiver-two ways to implement.
package com.example.broadcastreceiver;
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
UserDefinedBroadcastReceiver broadCastReceiver = new UserDefinedBroadcastReceiver();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* This method enables the Broadcast receiver for
* "android.intent.action.TIME_TICK" intent. This intent get
* broadcasted every minute.
*
* #param view
*/
public void registerBroadcastReceiver(View view) {
this.registerReceiver(broadCastReceiver, new IntentFilter(
"android.intent.action.TIME_TICK"));
Toast.makeText(this, "Registered broadcast receiver", Toast.LENGTH_SHORT)
.show();
}
/**
* This method disables the Broadcast receiver
*
* #param view
*/
public void unregisterBroadcastReceiver(View view) {
this.unregisterReceiver(broadCastReceiver);
Toast.makeText(this, "unregistered broadcst receiver", Toast.LENGTH_SHORT)
.show();
}
}
Two choices
1) If you want to read Broadcast only when the Activity is visible
then,
registerReceiver(...) in onStart() and unregisterReceiver(...) in onStop()
2) If you want to read Broadcast even if Activity is in Background
then,
registerReceiver(...) in onCreate(...) and unregisterReceiver(...) in onDestroy()
Bonus:
If you are lazy
If you don't want to write boilerplate code for registering and unregistering a BroadcastReceiver again and again in each Activity then,
Create an abstract Activity
Write boilerplate code in Activity
Leave the implementation as abstract methods
Here is the code snippet:
Abstract Activity
public abstract class BasicActivity extends AppCompatActivity {
private BroadcastReceiver broadcastReceiver;
private IntentFilter filter;
private static final String TAG = "BasicActivity";
/**********************************************************************
* Boilerplate code
**********************************************************************/
#Override
public void onCreate(Bundle sis){
super.onCreate(sis);
broadcastReceiver = getBroadcastReceiver();
filter = getFilter();
}
#Override
public void onStart(){
super.onStart();
register();
}
#Override
public void onStop(){
super.onStop();
unregister();
}
private void register(){
registerReceiver(broadcastReceiver,filter);
}
private void unregister(){
unregisterReceiver(broadcastReceiver);
}
/**********************************************************************
* Abstract methods
**********************************************************************/
public abstract BroadcastReceiver getBroadcastReceiver();
public abstract IntentFilter getFilter();
}
Using this approach you can write more boilerplate code such as
writing common animations, binding to a service, etc.
See full code:
HERE
According to Listening For and Broadcasting Global Messages, and Setting Alarms in Common Tasks and How to Do Them in Android:
If the receiving class is not
registered using in its
manifest, you can dynamically
instantiate and register a receiver by
calling Context.registerReceiver().
Take a look at registerReceiver (BroadcastReceiver receiver, IntentFilter filter) for more info.
It is best practice to always supply the permission when registering the receiver, otherwise you will receive for any application that sends a matching intent. This can allow malicious apps to broadcast to your receiver.
for LocalBroadcastManager
Intent intent = new Intent("any.action.string");
LocalBroadcastManager.getInstance(context).
sendBroadcast(intent);
and register in onResume
LocalBroadcastManager.getInstance(
ActivityName.this).registerReceiver(chatCountBroadcastReceiver, filter);
and Unregister it onStop
LocalBroadcastManager.getInstance(
ActivityName.this).unregisterReceiver(chatCountBroadcastReceiver);
and recieve it ..
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("mBroadcastReceiver", "onReceive");
}
};
where IntentFilter is
new IntentFilter("any.action.string")
Create a broadcast receiver
[BroadcastReceiver(Enabled = true, Exported = false)]
public class BCReceiver : BroadcastReceiver
{
BCReceiver receiver;
public override void OnReceive(Context context, Intent intent)
{
//Do something here
}
}
From your activity add this code:
LocalBroadcastManager.getInstance(ApplicationContext)
.registerReceiver(receiver, filter);