【问题标题】:Race condition when detecting connectivity status change in Android在 Android 中检测连接状态变化时的竞争条件
【发布时间】:2017-01-23 13:01:21
【问题描述】:

我需要监控并确定我的 Android 应用中的连接状态变化。为此,我已将我的班级注册为广播接收器:

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(this, filter);

现在,为了确定连接状态,您可以执行以下操作:

@Override
public void onReceive(Context context, Intent intent) {
  if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
    return;
  }
  NetworkInfo aNetworkInfo =
      intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
  if (aNetworkInfo == null) {
    return;
  }

  boolean isConnected = aNetworkInfo.isConnected();
  int networkType = aNetworkInfo.getType();
  // by using isConnected & networkType, get the new connectivity status..
}

问题是 ConnectivityManager.EXTRA_NETWORK_INFO 已被弃用。现在,建议您使用CONNECTIVITY_SERVICEgetActiveNetworkInfo(),类似这样:

@Override
public void onReceive(Context context, Intent intent) {
  if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
    return;
  }
  ConnectivityManager connManager = 
      (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  if (connManager == null) {
    return;
  }
  NetworkInfo activeNetworkInfo = connManager.getActiveNetworkInfo();
  boolean isConnected =
      (activeNetworkInfo != null) && activeNetworkInfo.isConnected();
  int networkType =
      (activeNetworkInfo != null) ? activeNetworkInfo.getType() : -1;
  // by using isConnected & networkType, get the new connectivity status..
}

这提出了以下问题:

在第二个实现中,当使用 CONNECTIVITY_SERVICE EXTRA_NETWORK_INFO:

是否有机会出现竞争条件?由于onReceive是异步调用的,当从连接服务获取网络信息时,连接状态可能与意图中的网络信息不同(因为连接可能同时发生变化)? 意思是,在使用意图时,我确信网络信息包含触发onReceive 的数据,但是在使用服务时 - 网络信息可能会有所不同...?

如果是这样,获取触发onReceive 的信息的最佳方式是什么? 此外,如果这样做的唯一方法是继续使用意图 - 这不是两个事实来源吗? (一个来自连接服务,一个来自发送的意图......)

更新:

可能的竞争条件示例:

有人连接到 WiFi 后立即断开了 WiFi 连接。这将导致发送 2 个意图(一个用于连接到 WiFi,一个用于断开与 WiFi 的连接。实际上发送了更多意图,但我将重点关注这 2 个)。我要问的可能的竞争条件是:当我们获得第一个意图(WiFi 连接)时,额外的意图EXTRA_NETWORK_INFO 将导致isConnected = truenetworkType = TYPE_WIFI。但是,当我从连接服务获取数据时,是否有可能因为 onReceive 被异步调用,WiFi 已经断开连接,导致 isConnected = falsenetworkType = TYPE_WIFI 而意图仍然为此保留正确的值打电话给onReceive?或者这总是会发生得足够快,以便您从 onReceive.. 中的连接服务获得正确的值?

【问题讨论】:

    标签: android networking race-condition connectivity


    【解决方案1】:

    我的解决方案是在每次连接更改时发送一个广播,如果连接状态为 up 或 down,则添加一个额外的广播,希望它有所帮助:

    public class ConnectivityChangeReceiver extends BroadcastReceiver {
    
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(context.getClass().getName(), " Changed connection ");
        context.sendBroadcast(new Intent(MyApplication.ACTION_CONNECTION_CHANGED)
                .putExtra(MyApplication.INTENT_EXTRA_CONNECTION_STATUS,NetWorkUtils.isNetworkAvailable(context)));
    }}
    
    
    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager cm =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null &&
                activeNetwork.isConnectedOrConnecting();
    }
    

    Android 清单:

    <receiver android:name=".ConnectivityChangeReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>
    

    【讨论】:

    • 再说一次 - 您使用的是连接服务,而不是发送意图中的信息 -> 所以问题仍然存在(来自服务的信息将始终与意图中的信息相同,或者竞争条件可能导致此信息不同?)
    • 根据文档,您可以使用额外的内容来了解​​网络状态,但我选择了直接的解决方案,以确保每次接收时都检查。
    • 在 CONNECTIVITY_ACTION 检查developer.android.com/reference/android/net/…
    • 是的,我已经看过文档 - 但同样,不推荐使用额外的 EXTRA_NETWORK_INFO -> 建议您应该使用连接服务。但是,我的问题仍然存在:竞争条件是否可能?我们从onReceive 中的连接服务获得的数据是否可能与intent extra 中的数据不同,因为onReceive 是异步调用的?
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-14
    • 2015-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多