Как получить уведомление, когда устройство теряет сетевое подключение в android L (API 21)
Я использую этот код, чтобы получать уведомления о потере соединения в API 20 и ниже.
registerReceiver(getConnectivityStateBroadcastReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
private class ConnectivityStateBroadcastReceiver extends BaseBroadcastReceiver {
/**
* @param userLoggedIn
* @param context
* @param intent
*/
@Override
protected void onReceive(Boolean userLoggedIn, Context context, Intent intent) {
Bundle extras = intent.getExtras();
boolean notConnected = extras.getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
// DO something
}
}
но это не работает в API 21.
Как я могу это исправить? может быть, это связано с ConnectivityManager.NetworkCallbak, но я не нашел ни одного примера, как его использовать. Благодарю.
Ответы
Ответ 1
ОК, поэтому я выясню, как это сделать, но будет благодарен за подтверждение того, что это решение является правильным.
Все, что я сделал, это добавить вызов этого кода в onCreate моего класса приложения
/**
*
*/
@SuppressLint("NewApi")
private void registerConnectivityNetworkMonitorForAPI21AndUp() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
connectivityManager.registerNetworkCallback(
builder.build(),
new ConnectivityManager.NetworkCallback() {
/**
* @param network
*/
@Override
public void onAvailable(Network network) {
sendBroadcast(
getConnectivityIntent(false)
);
}
/**
* @param network
*/
@Override
public void onLost(Network network) {
sendBroadcast(
getConnectivityIntent(true)
);
}
}
);
}
/**
* @param noConnection
* @return
*/
private Intent getConnectivityIntent(boolean noConnection) {
Intent intent = new Intent();
intent.setAction("mypackage.CONNECTIVITY_CHANGE");
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, noConnection);
return intent;
}
а в IntentFilter, который уже отслеживает мои подключения для API 20 и меньше, я добавил этот
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction("mypackage.CONNECTIVITY_CHANGE");
и теперь мой уже работающий широковещательный приемник получает уведомление об изменениях сети в API 21.
Ответ 2
Я вставлю свое полное решение, так как мне нужно было искать во многих местах, чтобы заставить его работать:
В классе приложений
public void onCreate(){
...
IntentFilter filter = new IntentFilter();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Timber.d("using registerNetworkCallback");
createChangeConnectivityMonitor();
filter.addAction(MY_CONNECTIVITY_CHANGE);
} else {
Timber.d("using old broadcast receiver");
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
}
registerReceiver(new SyncOnConnectivityReceiver(), filter);
}
@RequiresApi(Build.VERSION_CODES.N)
private void createChangeConnectivityMonitor() {
final Intent intent = new Intent(MY_CONNECTIVITY_CHANGE);
ConnectivityManager connectivityManager = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
connectivityManager.registerNetworkCallback(
new NetworkRequest.Builder().build(),
new ConnectivityManager.NetworkCallback() {
/**
* @param network
*/
@Override
public void onAvailable(Network network) {
Timber.d("On available network");
sendBroadcast(intent);
}
/**
* @param network
*/
@Override
public void onLost(Network network) {
Timber.d("On not available network");
sendBroadcast(intent);
}
});
}
}
В моем приемнике:
public class SyncOnConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(@Nullable final Context context, Intent intent) {
Timber.d("triggering on connectivity change");
if (context != null && isNetworkAvailable(context)) {
Executors.newSingleThreadExecutor().submit(new Runnable() {
@Override
public void run() {
syncBusData(context);
}
});
}
}
private boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm != null) {
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
return false;
}
private void syncData(Context context) {
}
}
В AndroidManizest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<receiver android:name="com.innofied.viapool.location.SyncOnConnectivityReceiver"/>
Ответ 3
Добавление к выше ответа:
Более подробную информацию о том, как обрабатывать статус сети в Lollipop, можно найти по адресу
https://developer.android.com/about/versions/android-5.0.html
Ответ 4
Попробуйте это, если вам нужно
- зарегистрировать изменения состояния сети
- рассмотреть все сетевые интерфейсы
- хотите получать уведомления, если сеть доступна для любого интерфейса
- этот код поддерживает API> 20 (вы также можете легко добавить поддержку старого API)
Объявите необходимые переменные в своем классе:
private static final HashMap<Network, Boolean> mNetworkStates = new HashMap<>();
private final Object mSyncNetworkState = new Object();
private Boolean mNetworkState;
Определите свой метод, который отслеживает изменения интерфейса. mNetworkState всегда показывает, подключен ли хотя бы один сетевой интерфейс.
private void registerNetworkStateInfo(@NonNull final Context context) throws Exception {
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
if (connectivityManager != null) {
connectivityManager.registerNetworkCallback(
builder.build(),
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
mNetworkStates.put(network, true);
synchronized (mSyncNetworkState){
mNetworkState = true;
}
Log.d("Network state", "Network state: true");
}
@Override
public void onLost(@NonNull Network network) {
mNetworkStates.put(network, false);
synchronized (mSyncNetworkState){
mNetworkState = false;
Log.d("Network state", "Network state: false");
mNetworkStates.forEach(new BiConsumer<Network, Boolean>() {
@Override
public void accept(Network nextNetwork, Boolean state) {
if (state.equals(true)) {
mNetworkState= true;
Log.d("Network state", "Network state: but true");
}
}
});
}
}
}
);
} else {
synchronized (mSyncNetworkState){
mNetworkState = false;
}
throw new Exception("Connectivity Manager is not available");
}
}
Используйте свой mNetworkState
synchronized (mSyncNetworkState){
if (!mNetworkState) {
throw new Exception("No network available");
}
}