In my application I have to get notified whenever the device connects or disconnects from a WIFI network. For this I have to use a BroadcastReceiver but after reading through different articles and questions here on SO I'm a bit confused which Broadcast action I should use for this. In my opinion I have three choices:
SUPPLICANT_CONNECTION_CHANGE_ACTION
NETWORK_STATE_CHANGED_ACTION
CONNECTIVITY_ACTION
To reduce resources I really only want to get notified whenever the device is CONNECTED to a WIFI network (and it has received an IP address) or when the device has DISCONNECTED from one. I do not care about the other states like CONNECTING etc.
So what do you think is the best Broadcast action I should use for this? And do I have to manully filter the events (because I receieve more then CONNECTED and DISCONNECTED) in onReceive?
EDIT: As I pointed out in a comment below I think SUPPLICANT_CONNECTION_CHANGE_ACTION would be the best choice for me but it is never fired or received by my application. Others have the same problem with this broadcast but a real solution for this is never proposed (in fact other broadcasts are used). Any ideas for this?
You can go for WifiManager.NETWORK_STATE_CHANGED_ACTION works.
Register receiver with WifiManager.NETWORK_STATE_CHANGED_ACTION Action, either in Manifest or Fragment or Activity, which ever suited for you.
Override receiver :
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean connected = info.isConnected();
if (connected)
//call your method
}
}
Please try
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction("android.net.wifi.STATE_CHANGE");
registerReceiver(networkChangeReceiver, filter);
}
#Override
protected void onDestroy() {
unregisterReceiver(networkChangeReceiver);
super.onDestroy();
}
and
BroadcastReceiver networkChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (!AppUtils.hasNetworkConnection(context)) {
showSnackBarToast(getNetworkErrorMessage());
}
}
};
I am using this and it is working for me. Hope it will help you out.
I have a simple Fragment within my Activity in which I enable and disable Bluetooth adapter and I want to listen to Bluetooth Adapter state changes with a BroadcastReceiver from within the Fragment. The reason is that I want to directly change the Fragment's UI elements upon Bluetooth state change. This is my code:
public class FragmentBT extends Fragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
IntentFilter iFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(BtStateChangedReceiver, iFilter);
}
#Override
public void onDestroy()
{
super.onDestroy();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(BtStateChangedReceiver);
}
public BroadcastReceiver BtStateChangedReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
... change UI based on the extra data from intent ...
}
}
}
When I enable or disable BT in my device using Action Buttons in my Fragment's ActionBar, the BT goes on and off, but my receiver never gets called. I never get into the receiver's onReceive method. I realize this is a pretty common question here, but I tried the sollutions from several but neither worked (and all are incorporated into my current code).
Thank you for any advice!
Try this:
getActivity().registerReceiver(BtStateChangedReceiver, iFilter);
getActivity().unregisterReceiver(BtStateChangedReceiver);
The docs say that 'LocalBroadcastManager' is used to 'register for and send broadcasts of Intents to local objects within your process'.
I've got an IntentService which should perform some tasks after WiFi has been turned on.
I'm using a BroadcastReceiver on WifiManager.WIFI_STATE_CHANGED_ACTION to listen for WiFi changes.
The problem:
When I turn on WiFi via wifiManager.setWifiEnabled(true) the BroadcastReceiver only receives the states WifiManager.WIFI_STATE_DISABLED and WifiManager.WIFI_STATE_ENABLING. Then the IntentService is destroyed before the actual WifiManager.WIFI_STATE_ENABLED state can be received.
If I put Thread.sleep(2000) at the end of onHandleIntent() it works, but there must be a better solution?
Questions:
Why is the state WifiManager.WIFI_STATE_DISABLED broadcasted at all when I'm calling wifiManager.setWifiEnabled(true)?
How can I make the onHandleIntent() method wait until the state WifiManager.WIFI_STATE_ENABLED has been retrieved?
Code:
public class BackupService extends IntentService {
private BroadcastReceiver mWifiStateChangedReceiver;
public BackupService() {
super("BackupService");
}
#Override
protected void onHandleIntent(Intent intent) {
final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
mWifiStateChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int wifiState = intent.getIntExtra(
WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
// PERFORM TASK...
}
}
};
registerReceiver(mWifiStateChangedReceiver, new IntentFilter(
WifiManager.WIFI_STATE_CHANGED_ACTION));
wifiManager.setWifiEnabled(true);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mWifiStateChangedReceiver != null) {
unregisterReceiver(mWifiStateChangedReceiver);
}
}
}
How can I make the onHandleIntent() method wait until the state WifiManager.WIFI_STATE_ENABLED has been retrieved?
Ideally, you don't, as WiFi may not be available, and so you may never receive such a broadcast.
Instead:
Move your BroadcastReceiver to be one registered in the manifest, initially disabled
If the IntentService determines that it needs to wait for WiFi, have it enable the existing BroadcastReceiver via PackageManager and setComponentEnabledSetting(), then return out of onHandleIntent()
The BroadcastReceiver would use startService() to send a command to be processed by your IntentService once WiFi is ready, at which point it can then disable itself via PackageManager and setComponentEnabledSetting()
I am checking Internet connectivity in my app using BroadcastReceiver and I show an alert dialog if the connection is lost. It works fine. But my problem is that BroadcastReceiver works even if my app is in backgroung. So dialog pops up when internet connection is lost even if user is in some other app. This is totally ruining my app.
Has anyone got any idea how to restrict Broadcast receiver in the app only?
Here is my BroadcastReceiver :
public class ConnectivityChangedReceiver extends BroadcastReceiver{
#Override
public void onReceive( Context context, Intent intent )
{
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
} else {
try{
Intent i=new Intent(context, InternetDialogActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
} catch(Exception e){
e.printStackTrace();
}
}
}
}
And the activity is:
public class InternetDialogActivity extends Activity implements OnClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.internet_dialog_box);
getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
Button retryButton = (Button) findViewById(R.id.retryInternetButton);
retryButton.setOnClickListener(this);
}
public boolean checkConnectivity(){
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo!=null && networkInfo.isConnected()) {
finish();
return true;
} else {
Intent intent = getIntent();
finish();
startActivity(intent);
return false;
}
}
#Override
public void onClick(View view) {
switch(view.getId()){
case R.id.retryInternetButton:
try{
checkConnectivity();
} catch(Exception e){
e.printStackTrace();
}
break;
}
}
}
Here is how I declared receiver and activity in manifest:
<receiver android:name="com.lisnx.service.ConnectivityChangedReceiver"
android:label="NetworkConnection">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<activity android:name="com.lisnx.activity.InternetDialogActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="#android:style/Theme.Dialog" />
I have read that we can restrict BroadcastReceiver to work within the app by not declaring it in the manifest. But I don't know how will receiver work then? Please help me. I am stuck on it badly. Thanx in advance.
A BroadcastReceiver works when the app is in the background because the event that the receiver picks up are sent globally, and each app is registered to listen in on these, regardless of whether or not it is running.
To deal with this, in your BroadcastReceiver's onReceive code, check if your app is in the foreground.
There is one--and only one that I know of--consistently effective method to do this. You need to keep track of your pause/resume actions for your application. Ensure that you check this in every activity.
There is some sample code in this answer (solution #1). In your case, you would want to check MyApplication.isActivityVisible() == true as a validation before doing anything from your BroadcastReceiver.
Have you tried to remove the Intent filter from the manifest and register/unregister it in activity? So you can try to register Intent filter in onStart() and unregister it on onStop() methods. The code goes somethink like this:
static final String ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
IntentFilter filter = new IntentFilter(ACTION);
this.registerReceiver(ConnectivityChangedReceiver, filter);
unregisterReceiver(ConnectivityChangedReceiver);
You should also learn about Activity Lifecycle, if it's not familiar yet.
You should register/unregister your BroadcastReceiver in onPause() and onResume() of each activity. Then you know that the receiver is only "listening" when your app is in the foreground. You can easily do that by creating your own BaseActivity that extends Activity and overrides onPause() and onResume() and registers/unregisters your receiver. Just have all your activities extend BaseActivity and have them call through to super.onResume() and super.onPause() as usual. Here's example code:
public class BaseActivity extends Activity {
// Create an IntentFilter to listen for connectivity change events
static IntentFilter filter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
// Create an instance of our BroadcastReceiver
static ConnectivityChangedReceiver receiver = new ConnectivityChangedReceiver();
#Override
protected void onPause() {
super.onPause();
// Stop listening for connectivity change events
unregisterReceiver(receiver);
}
#Override
protected void onResume() {
super.onResume();
// Listen for connectivity change events
registerReceiver(receiver, filter);
}
}
All your activities should extend BaseActivity and if they need to do anything special in onResume() or onPause() just make sure to call through to super.onXXXXX() like this:
public MyActivity extends BaseActivity {
#Override
protected void onResume() {
super.onResume();
// Here you do whatever you need to do in onResume() of your activity
...
}
#Override
protected void onPause() {
super.onPause();
// Here you do whatever you need to do in onPause() of your activity
...
}
}
I didn't run the code through a compiler so I apologize if there's a typo or I missed something.
I think you will have to make sure that you are not using the receiver when app is in background. For that you will have to use every activities onPause() and onResume() methods.
As far as I know, if Broadcast receiver is registered inside manifest.xml then broadcast receiver exists as long as application exists. Also, Dynamically registered receivers (that means, Register your BroadcastReceiver programmatically) are called on the UI thread. This means that your receivers blocks any UI handling and thus the onReceive() method should be as fast as possible.
However, I will try to discuss information about Broadcast Receiver. But, first should know some information. Firstly, Broadcast receiver is a standalone application component which means it will continue running even when other application component are not running. That's why we unregister broadcast receiver in onPause on the activity. Also, Developer should register this in Activity.onResume() implementation.
Secondly, Developer should not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack. I have put that information from BroadcastReceiver documentation.
Another point is that a BroadcastReceiver object is only valid for the duration of the call to onReceive(). As soon as the onReceive() method is finished, your BroadcastReceiver terminates.
Now, how to register your receiver programmatically:
public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
Here, BroadcastReceiver- receiver will be call when any broadcast intent match with filter.
And IntentFilter- Intent specifies which event your receiver should listen to.
Register:
YourConnectionListener receiver;
this.reciever = new YourConnectionListener();
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(this.reciever, filter);
Sent your Broadcast Info:
Intent intent = new Intent();
intent.putExtra("Message", "Your connectivity info has Changed!!");
this.sendBroadcast(intent);
Receiver:
Now, need to receive the Broadcast. Android calls the onReceive() method on all registered broadcast receivers whenever the event occurs. Say you want to be notified whenever the connection is changed.
public class YourConnectionListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
// your Code
}
}
onReceive() has two arguments:
context: The Context object you can use to access additional information or to start services or activities.
intent: Intent used to register your receiver. This object contains additional information that you can use in your implementation.
Additionally, Developer should avoid any long-lasting tasks in your BroadcastReceiver. So, In statically and dynamically registered receivers, Developer should do minor tasks in the receiver itself.For any longer tasks you should start a service from within your receiver.
To make a Broadcast Receiver that fires only when you app is running follow the below code.
1. Create your Broadcast Receiver like this:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class InternetStatusNotifier extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//Recieve notification here
}
}
2. Make an activity or fragment where you want the Broadcast Receiver to work like this:
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
public class MainActivity extends Activity {
private InternetStatusNotifier mInternetStatusNotifier;
#Override
protected void onCreate(Bundle savedInstanceState) {
mInternetStatusNotifier = new InternetStatusNotifier();
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
registerReceiver(mInternetStatusNotifier, new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE"));
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(mInternetStatusNotifier);
super.onPause();
}
Note: That is how you use broadcasts receiver in a screen specific manner. Only the screen displaying will receive broadcasts in this way. When you register broadcast using manifest file then they are even received when app is closed
That is the way broadcast receivers work in Android. If you register for a broadcast in the manifest and your app is not running, Android will start a new process to handle the broadcast. It is generally a bad idea to directly show a UI from a broadcast receiver, because this may interrupt other apps. I'm also not convinced that a universal 'connection lost' dialog is a good idea either. This should probably be handled by each activity that uses network access.
As for the original question, you need to disable your receiver when your activity goes in the background (onPause(), etc.) and enable it when you come to the foreground (onResume(), etc). Put enabled=false in your manifest and then use something like this in your code to toggle it as necessary:
public static void toggle(Context context, boolean enable) {
int flag = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
ComponentName receiver = new ComponentName(context,
ConnectivityMonitor.class);
context.getPackageManager().setComponentEnabledSetting(receiver, flag,
PackageManager.DONT_KILL_APP);
}
A simple way of finding whether the app is in foreground or not
if((mContext.getPackageName().equalsIgnoreCase(
((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}
I better suggest you to check the internet setting from the application when someone opens it, here is the piece of code how i do it.
public static boolean isNetworkConnected(Context ctx) {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null) {
return false; // There are no active networks.
} else
return true;
}
So I have a small little app which downloads a very small amount of data from the net. Everything else works just fine and downloads properly, but when connection changes (I lose wifi range) the download won't complete and the user doesn't get their data.
I have an idea how to handle this. I set up a BroadcastReceiver on my main Activity which communicates with my IntentService. When the IntentService completes the download, I then unregister the receiver. To top all this, I set up a Broadcastreceiver to listen connectivity changes and if connection is available, and if there is a connection, the main activity sends an Intent to start the download. See here:
Main Activity:
public class Sample extends Activity {
private BroadcastReceiver connectivityReceiver;
private ResponseReceiver receiver;
protected void onCreate(Bundle sis){
super.onCreate(sis);
IntentFilter intentFilter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (Network.isOnline()) {
fireUpDownloadingIntent();
}
}
}, intentFilter);
}
public class ResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP = "com.irough.intent.action.URL_LOADED";
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getBooleanExtra(DLService.DOWNLOAD_COMPLETE, false) {
unRegisterReceiver(connectivityReceiver);
}
}
}
}
DLService.java:
public class DLService extends IntentService {
public static final String DOWNLOAD_COMPLETE = "dlc";
public DLService() {
super("DLService");
}
#Override
protected void onHandleIntent(Intent intent) {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(ResponseReceiver.ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra(DOWNLOAD_COMPLETE, true);
sendBroadcast(broadcastIntent);
}
}
The code about should work just fine, but is there an easier or better way to do it? Doesn't have to be done on Service, Asynctask force closes on me when connection drops and that's why put the download action to a service.
If you lose the connection in your download, I imagine your download will throw some sort of exception. If I were, I'd simply notify the user (using the android notification api), and give them the option to try to redownload the data.
Preferably though, (and contrary to my previous post in a similar question), you could use my new favorite class in the android, the AsyncTaskLoader. It sounds like it exactly fits the bill for what you want to do here. Bascially, if there's an error downloading, just have your loader return null. Then in your onLoaderFinished hook in your activity, do what ever you need to do in regards to informing the user. Note that this class is only available to API levels 3 and above, but can still be accessed by lower API levels through the android compatibility package.