Trying to monitor the offline state of the app by using a broadcast receiver on android.net.conn.CONNECTIVITY_CHANGE but I’m experiencing a huge delay in the connection change when switching on and off the airplane mode, 20 - 30 seconds, is there any faster way? (without polling the connection)
Manifest:
<receiver android:name=".service.NetworkStateReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
Receiver:
public class NetworkStateReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "\t\t\tCONNECTIVITY CHANGED");
}
}
EDIT: there is a D/NetworkChangeNotifierAutoDetect: Network connectivity changed, type is: 5 log in the logcat that is almost instant, is there a way to capture something that triggers that log?
EDIT: found that android.intent.action.SERVICE_STATE is actually way quicker for reconnection. Dropping connection change still 20 to 30s delay :(
Related
We use broadcasts to communicate state changes between a remote services and our UI. Doing this, we discovered a very strange behaviour: Sometimes (I can not find any clues why) these broadcasts are delayed around 8s.
How we send them (pretty basic, mState is just a enum) (Remote process in service):
Intent intent = new Intent();
intent.setAction(ACTION_STATE_CHANGED);
intent.putExtra(EXTRA_STATE, mState);
Service.get().sendBroadcast(intent, null);
How the static receiver is registered (App):
<receiver android:name=".ServiceStateReceiver">
<intent-filter>
<action android:name="service.intent.action.STATE_CHANGE" />
</intent-filter>
</receiver>
The receiver class (App):
public class ServiceStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.v("State", "State via static received");
}
}
This is now sometimes delayed (always for the same states)
State enum:
public enum State {
DISCONNECTED,
BT_DISABLED,
BT_SCANNING,
BT_TIMEOUT,
BT_FAILURE,
BT_LOCATION_NEEDED,
CONNECTING,
ACTIVATION_FAILURE,
VIN_NEEDED,
CAR_MODEL_NEEDED,
MILEAGE_NEEDED,
READY,
IGNITION_OFF,
IGNITION_ON;
#Override
public String toString() {
return name();
}
}
Now comes the strange part: If I register a dynamic receiver we always receive ALL broadcasts immediately there. The static one still has that huge delay. If I send the broadcast via sendOrderedBroadcast BOTH (static & dynamic) have this delay.
Dynamic receiver:
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("State", "State via dynamic received");
}
}, new IntentFilter(State.ACTION_STATE_CHANGED));
What I tried so far:
send the broadcast from the main thread/a worker thread (nothing changed)
played with the permission attribute (nothing changed)
send the broadcast multiple times in a row (not changing anything, just getting multiple delayed broadcasts now)
Also: No output from logcat which seems related. Tried on different devices (OnePlus 3 7.1.1, Z3 6.0.1, S7 Edge 7.1.1), all show the same behaviour
I think this may be related: Android network state change detection takes time
After searching for a answer for hours, I found the? solution after posting this.
It seems like that adding the FLAG_RECEIVER_FOREGROUND flag to the intent completly removes this delay. Would be still nice to know why this happens and if this is a good "fix" or if I destroy something else with this.
This does the trick:
intent.setFlags(FLAG_RECEIVER_FOREGROUND);
If set, when sending a broadcast the recipient is allowed to run at
foreground priority, with a shorter timeout interval. During normal
broadcasts the receivers are not automatically hoisted out of the
background priority class.
Source:
https://developer.android.com/reference/android/content/Intent.html#FLAG_RECEIVER_FOREGROUND
I made this broadcast receiver
public class DateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("DATE RECEIVER", "OK");
}
}
registered in manifest
<receiver
android:name=".DateReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.DATE_CHANGED" />
</intent-filter>
</receiver>
It works when device is on but if I turn it off and wait for midnight to pass, then I don't get any intent at reboot. How should I get it?
You won't get this broadcast because date has NOT changed (unless i.e. there's time update after the boot). It is different but has not changed in the way that justifies this broadcast. This may be confusing but in fact it does not matter what time stamp is when device starts. As device was started it does not know if that was because of restart or it was off for 5 weeks. Broadcast will be send if time is artificially changed i.e. due to network time sync, manual time change via preferences, timezone change. Normal ticking does not count. Initial time stamp does not matter.
If you need to know date on boot, you should listen to BOOT_COMPLETED.
You also need to remove android:exported="false" or set it to true as otherwise it is not reachable.
Is there anyway to detect hthe camera button in Sleep mode? I tried the examples explained in this forum, but nothing works in Sleep mode.. I am llooking for this for a long time, but no proper answers..
How I can receive hardware key events in sleep mode?
Please help me...
public class YourBoardcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_CAMERA_BUTTON.equals(intent.getAction())) {
Intent main = new Intent();//
}
}
}
And in your Manifest :
<receiver android:name="YourBoardcastReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON" />
</intent-filter>
</receiver>
This is not possible. When the device is put in sleep mode, almost all apps are paused or stopped. Only enough of the processor is kept on to be able to receive calls and SMS texts, and manage alarms and notifications. Apart from that, pretty much everything is discontinued.
If you want to keep detecting it when the screen is off, you will need to acquire a wakelock to prevent the device from going into sleep. However, if you do this all the time it will have an impact on the users' battery life.
I want to check the internet connection constantly and close the app with a warning message if connection is lost. How can i manage to do that?
Check Internet Connectivity via Phone Background service (such as AlermManager Service) then close the app if no connection found.
thanks.
close the app
Don't try to kill the process and its not recommended way of closing application. Either call finish() on all activities or call moveTaskToBack(true).
For Solution
Here you go.
You will need to register for and handle BroadCastReceiver android.net.conn.CONNECTIVITY_CHANGE
Step 1
Include following permission in manifest
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Step2
Let Android know which class will be register for BroadCast Receiver.
<receiver android:name="ConnectivityReceiver_package_name.ConnectivityReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Step 3
Put your logic for various Network States.
public class ConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,false);
if(noConnectivity){
//Show Warning Message
//Close Application the way i suggested
}
}
}
As my code looks today, I'm periodically sending a alarm(?) using AlarmManager that is received by AlarmReceiver extends BroadcastReceiver which in turn starts a Service. The Service do some updating and ends with a stopSelf(). IMO this is the best way of periodically perfom a task without constantly having a Service running. Correct?
The issue with this code is however that the whole chain of events is initiated onSharedPreferenceChanged(). I (initially) thought this was a good idea since the whole updating thing is enabled by the user in SharedPreferences.
I've now come to the conclusion that this is in fact not very good and that I need to initiate the AlarmManager/AlarmReceiver/Service/whatever both onPreferenceChange but also on boot.
I've done some searching but everyone seems to want to start the Service on boot. As I see it, I just need to initiate the AlarmManager which will then start the Service (when needed and only periodically).
Please help me with, first of all, sorting this out and secondly coding it!
Thanks in advance!
Then, create and register a BroadcastReceiver where you will do the AlarmManager stuff:
public class YourBootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// do the AlarmManager here
}
}
Then, on your manifest:
<application>
... other stuff
<receiver android:name=".YourBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />