【问题标题】:How can I receive a notification when the device loses network connectivity in android L (API 21)当设备在 android L (API 21) 中失去网络连接时如何接收通知
【发布时间】:2019-09-19 00:05:40
【问题描述】:

我正在使用此代码在 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 有关,但我没有找到任何使用它的示例。谢谢。

【问题讨论】:

  • 你可以创建一个在运行时递归运行的线程尝试连接到网络,当你从它捕获一个 NetworkException 时,你就失去了连接
  • 这听起来像是一个非常错误的方法。
  • 我在工作中使用的是我自己的,没有错误也没有超载
  • 好吧,我宁愿使用内置功能

标签: android android-5.0-lollipop


【解决方案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;

}

在已经监控我的 API 20 和更少的连接的 IntentFilter 中,我添加了这个

IntentFilter filter = new IntentFilter();

filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction("mypackage.CONNECTIVITY_CHANGE");

现在我已经在工作的广播接收器也会收到有关 API 21 中网络更改的通知。

【讨论】:

  • 我实现了这个,发现在 Lolipop 5.0.1 中它没有捕捉到只有移动数据连接(没有 wifi)并且连接经历信号丢失(即开车进入隧道)的场景)。使用飞行模式强制断开设备连接或关闭移动数据将触发它。
  • 我也遇到了同样的问题,如果你发现有什么好吃的就点这里
  • 但请记住,CONNECTIVITY_ACTION 在 API 级别 28 中已弃用
  • 在某些情况下,当切换网络(例如从 lte 到 wifi)时,wifi 网络的 onAvailable 比 lte 的 onLost 更早。在这种情况下,最后一次广播会告诉我们网络丢失。
【解决方案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) {

}
}

在 AndroidManifiest.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"/>

【讨论】:

  • 但请记住,CONNECTIVITY_ACTION 在 API 级别 28 中已弃用
  • 但是这个回调什么时候取消注册?
【解决方案3】:

如果你需要试试这个

  • 注册网络状态变化
  • 考虑所有网络接口
  • 希望在网络可用于任何接口时收到通知
  • 该代码支持 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");
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 2014-04-19
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    相关资源
    最近更新 更多