I have this BroadcastReceiver implementation in my Fragment :
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo networkInfo =
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(networkInfo.isConnected()) {
//do stuff
}
//Other actions implementation
}
}
};
With standart register/unregister methods:
#Override
public void onStart() {
super.onStart();
getActivity().registerReceiver(receiver, getIntentFilter());
}
#Override
public void onStop() {
super.onStop();
getActivity().unregisterReceiver(receiver);
}
And receiver with same implementation for WifiManager.NETWORK_STATE_CHANGED_ACTION in other Fragment
The issue: this action triggers everytime one of the fragments started, but i need it to trigger only if Wifi was really just connected, and as the name of action says WifiManager.NETWORK_STATE_CHANGED_ACTION, so it should work only if Wifi state changes
Edit: as was replied this action will trigger every time by the default, so my question is: There is no action for Wifi connecting ?
That's how the WifiManager works when you register for NETWORK_STATE_CHANGED_ACTION. When you register it, you will get 1 update immediately, to show the current state.
To circumvent this, you could have a simple boolean in your fragment set as default to 'true'. In your broadcast receiver, check if this is true, and if so, it's the first time you get an update, set it to false and then simply ignore the update. The next time it's called, the boolean will be true and you can use the data.
private boolean firstTime = true;
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(firstTime) {
firstTime = false;
return;
}
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo networkInfo =
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(networkInfo.isConnected()) {
//do stuff
}
//Other actions implementation
}
}
};
The NETWORK_STATE_CHANGED_ACTION broadcast is likely "sticky", use the isInitialStickyBroadcast method check if the broadcast is the first "sticky" one:
#Override
public void onReceive (Context context, Intent intent) {
if (!isInitialStickyBroadcast()) {
// Only check updates in state
}
}
See "ConnectivityManager.NetworkCallback". This is only available in API 21 onward. This may not have the exact condition you are after, but is close.
Related
I've written an android app which checks the network status by using a BroadcastReceiver inherited class:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d("mylog", "NetworkChangeReceiver Hit");
}
}
which is registered in the manifest file like this:
<receiver
android:name="foo.NetworkChangeReceiver"
android:label="NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
I needed to handle the internet connection whenever it connects or disconnects. Actually, it works perfectly in normal situations.
But the problem is that when the application is closed manually (by minimizing the app and then closing it by swiping out the app icon in the Recents button menu), it still receives the network status changes. This sometimes causes some exceptions.
Even I have included all the code in receiver function in try/catch block, but still sometimes a toast message containing an error message is shown. This sometimes happen even after some days after the closure of the app.
Please note that the code in the receiver function is more complicated than the code that is shown here and has some access to internal classes and variables.
Your app will still receive events, even if it isn't running. Before you do anything in onReceive(), you can check if the activity is running by:
Option 1: Use a static variable in your activity to check it's state for access from the receiver :
public class YourActivity extends Activity {
public static boolean isRunning = false;
#Overrride
public void onCreate(Bundle savedInstanceState){
isRunning = true;
....
}
//We need receiver to work when app is minimized
/*
#Override
public void onStart() {
super.onStart();
isRunning = true;
}
#Override
public void onStop() {
super.onStop();
isRunning = false;
}
*/
}
And in the receiver:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d("mylog", "NetworkChangeReceiver Hit");
if(!YourActivity.isRunning)
return;
}
}
Option 2 : Using the ActivityManager
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (isAppForground(context))
return;
}
public boolean isAppForground(Context mContext) {
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(mContext.getPackageName())) {
return false;
}
}
return true;
}
}
You'll need the permission:
<uses-permission android:name="android.permission.GET_TASKS" />
If you define receivers in your manifest, the app will receive events, even if it is not started.
http://developer.android.com/guide/topics/manifest/receiver-element.html
Broadcast receivers enable applications to receive intents that are broadcast by the system or by other applications, even when other components of the application are not running.
To fix this, just don't define the Receiver in the manifest, but do it programatically in onStart and unregister it again in onStop. The problem with this solution is, that you won't get messages if your app is in the background.
private BroadcastReceiver receiver;
#Overrride
public void onStart(){
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
filter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
receiver = new NetworkChangeReceiver();
registerReceiver(receiver, filter);
}
#Override
protected void onStop() {
super.onStop();
//don't forget to unregister the receiver again
unregisterReceiver(receiver);
}
EDIT: onCreate and onDestroy won't work, as onDestroy will not be called in every instance the app is closed (e.g. if it is closed with the task manager)
Solution Found:
I found a perfect solution to my problem. Thanks to the correct answer in Android service crashes after app is swiped out of the recent apps list, I found out that when an app is closed via Recents list, the whole process will be created again and all the static variables will be freshed to their default values, and the onCreate and all other methods will not be called.
So the solution is something like:
public static boolean appStarted = false;
protected void onCreate(Bundle savedInstanceState) {
appStarted = true;
...
}
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (!MyActivity.appStarted)
return;
...
}
}
The key is to just keep track of when the app starts, and not when the app is closed (because the closing event of app is not dependable and in some situations doesn't work properly)
I'm using BroadcastReceiver class in android to get information about network change
using the following code:
class NetworkStatus extends BroadcastReceiver{
......
#Override
public void onReceive(Context context, Intent intent) {
}
public void startBroadCastReceiver()
{
}
public void StopBroadCastReceiver()
{
}
I want to stop the broadcast receiver and then start it again
How can I do this
Broadcast receiver likes event handler, Android system calls it automatically when a broadcast matches you defined intent. If you define the boardcast receiver in manifast file, I think the only way you can do it to return immediately when you don't want to handle the broadcast, like the following:
public void onReceive(Context context, Intent intent) {
if (stoppedBroadcast)
return;
// handle broadcast.
}
public void stopBroadcast {
stoppedBroadcast = true;
}
public void resumeBroadcast {
stoppedBroadcast = false;
}
If you want to stop recieving network changes try unregisterReciever in your registering activity/service.
When you want to enable recieving register the reciever with its IntentFilter again.
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 want to show the connection process on the screen when my device is connecting to the wifi network. SUPPLICANT_STATE_CHANGED_ACTION is provided by WifiManager but i don't know how to use it. Can anyone help me please?
You can indeed use the broadcasted intents for SUPPLICANT_STATE_CHANGED_ACTION:
The app needs the permission in its Manifest file:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Then register for the system broadcast:
MyWifiStateReceiver handler = new MyWifiStateReceiver();
context.registerReceiver(handler, new IntentFilter(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION));
the registerReceiver() needs an instance of a class implementing BroadcastReceiver as its first argument. In that code you can act on the Wifi state changes by overriding the onReceive method. For example
public class MyWifiStateReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION))
{
SupplicantState state = (SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
switch(state)
{
case COMPLETED:
case DISCONNECTED:
...
}
}
}
}
For the possible Wifi state values, see http://developer.android.com/reference/android/net/wifi/SupplicantState.html
I don't know of a callback method that lets you know when the wifi status has changed. I polled the information using a Handler running in the background.
Add the handler to your class.
private WifiStatusHandler wifiStatusHandler = new WifiStatusHandler();
Start it by calling
wifiStatusHandler.start();
The code I used is below.
/**
* Checks for wifi status updates.
*/
private class WifiStatusHandler extends Handler {
private boolean running = false;
public void handleMessage(Message message) {
if (running) {
//check wifi status here
WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
int curWifiState = wifiMgr.getWifiState();
SupplicantState info = wifiMgr.getConnectionInfo().getSupplicantState();
WifiInfo curWifi = wifiMgr.getConnectionInfo();
Log.i(TAG,"WIFI STATE = " + info.toString());
//update the TextView etc.
sleep();
}
}
private void sleep() {
removeMessages(0);
sendMessageDelayed(obtainMessage(0), REFRESH_DELAY);
}
public synchronized void start() {
running = true;
removeMessages(0);
sendMessageDelayed(obtainMessage(0), 0);
}
public synchronized void stop() {
running = false;
}
}
I have an app in which I'm trying to detect WHEN the Internet connection appears and when it disappears.
At the moment, when it appears, I'm starting a new thread (different from the UI) which connects my app to a remote server.
For that I'm hardly trying to implement a broadcast receiver which LISTENS for connectivity, but I'm having problems in understanding the concept.
In my onCreate() I have somethig like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
cThread.start();
}
When there is connection to the Internet I'm sending data through the socket, when there is not I'm storing the data in a database. And when the Internet appears I'm restarting my thread to reconnect and send the old data (which hasn't been sent because of network crashing) and the new one.
Let's say I would implement something like this:
DoRefreshBroadcastReceiver refreshBroadcastReceiver;
...
onResume() {
// register the refreshing complete broadcast receiver
IntentFilter intentFilter = new IntentFilter(DO_REFRESH);
refreshBroadcastReceiver = new doRefreshBroadcastReceiver();
registerReceiver(refreshBroadcastReceiver, intentFilter);
}
public class DoRefreshBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// call method to run fetch code...
}
}
Does this mean that when the Internet connection is detected my onReceive() gets called? And I could start my thread there?
What is the concept of using an intent? Because I really don't get it. How to use it, and what its purpose?
THE IDEA: I don't really know how to use this intent in this case or how to use it in my app!
Would this thing detect the connection to the Internet even when I'm not in this activity?
EDIT:
Here is how my onReceive looks like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
// cThread.start();
connIntentFilter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
public void onReceive(Context context, Intent intent)
{
mNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (mNetworkInfo != null && mNetworkInfo.isConnected())
{
/*
* if(mNetworkInfo.getType()==ConnectivityManager.TYPE_WIFI);
*
*
* else
*/
cThread.start();
}
else {
System.out.println("There is no internet connection!");
try {
cThread.stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
mNetworkInfo != null && mNetworkInfo.isConnected()
Does this mean it's connected or should I verify for a certain type of connection on the emulator?
*I think that I should start my thread directly in onReceive(). As soon as my app starts it detects the Internet connection and BroadcastReceiver gets fired, doesn't it?
Try something like this...
public class MyActivity extends Activity {
private MyConnectivityListener connListener = null;
private IntentFiler connIntentFilter = null;
private Boolean connIntentFilterIsRegistered = false;
#Override
protected void onCreate(...) {
...
connIntentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
#Override
protected void onResume() {
...
if (!connIntentFilterIsRegistered) {
registerReceiver(connListener, connIntentFilter);
connIntentFilterIsRegistered = true;
}
}
#Override
protected void onPause() {
...
if (connIntentFilterIsRegistered) {
unregisterReceiver(connListener);
connIntentFilterIsRegistered = false;
}
}
protected class MyConnectivityListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// The NetworkInfo for the affected network is sent
// as an extra; it should be consulted to see what
// kind of connectivity event occurred.
}
}
}
A BroadcastReceiver is effectively a 'listener' which listens for events either sent by the system or, in some cases, by your own application components.
In this case, the system broadcasts android.net.conn.CONNECTIVITY_CHANGE whenever there is a connection change (connected/disconnected). By registering your BroadcastReceiver to 'listen' for that event, you can get the extra included in the Intent from your BroadcastReceiver's onReceive(...) method and do whatever you need to do accordingly. The extra is a `NetworkInfo object which will contain information about the particular network and whether it is connected or not.