【问题标题】:How can I receive a notification when the device loses network connectivity?当设备失去网络连接时如何接收通知?
【发布时间】:2011-05-30 19:07:31
【问题描述】:

我知道您可以编写代码来确定设备是否连接到网络。

但在我的应用程序中,我想做的是在设备将其状态从“网络”更改为“无网络”时收到通知。例如,当用户进入隧道并失去信号等时,会发生这种情况。或者在使用 WiFi 时,用户超出接入点的范围,不再能够访问互联网。

Android API 是否提供了可以注册侦听器的功能,以便在每次网络状态发生变化时收到通知?

我找到了这段代码并尝试使用它,但它什么也没做。当网络状态发生变化时,我没有收到任何通知。

public class ConnectivityManager extends PhoneStateListener{

Activity activity;
public ConnectivityManager(Activity a){
    TelephonyManager telephonyManager = (TelephonyManager)a.getSystemService(Context.TELEPHONY_SERVICE);
    telephonyManager.listen(this, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
    activity = a;
}

@Override
public void onDataConnectionStateChanged(int state) {
    super.onDataConnectionStateChanged(state);
    switch (state) {
    case TelephonyManager.DATA_DISCONNECTED:
        new AlertDialog.Builder(activity).
        setCancelable(false).
        setTitle("Connection Manager").
        setMessage("There is no network connection. Please connect to internet and start again.").
        setNeutralButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                System.exit(0);
            }
        }).create();
        break;

    case TelephonyManager.DATA_CONNECTED:
        break;
    }
}
}

另外,我在 AndroidManifest.xml 中添加了相应的权限:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>

【问题讨论】:

  • 对于最新版本的 Android (API >= 24),请查看answer

标签: android


【解决方案1】:

您可能需要考虑使用BroadcastReceiver 代替ConnectivityManager.CONNECTIVITY_ACTION。来自文档:

网络连接发生了变化。连接已建立或丢失。受影响网络的 NetworkInfo 作为额外发送;应该咨询它以了解发生了什么样的连接事件。

此接收器适用于 WiFi 和蜂窝数据连接,与 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 不同,后者只会在蜂窝网络发生变化时通知您。

【讨论】:

  • 我相信正确的接收者是ConnectivityManager.CONNECTIVITY_ACTION
  • 嗯,是的,两者都可以。这是一个字符串常量,等于我发布的内容。我只是不记得常量名称。
  • @dwnz 奇怪的是 Google 让它离线了。视频可以still be found on YouTube。幻灯片是still online here(PDF 警告)。
  • 想象一下我们已经激活并运行了 WiFi。我们如何捕捉“移动数据”状态变化? (启用/禁用)。以接受的答案中提到的方式,它没有得到任何东西,ConnectivityManager.CONNECTIVITY_ACTION 广播听众也没有。
  • @GoRoS 我没有尝试过,但这听起来像是一个单独的问题。我对 OP 的阅读是,他们主要想知道他们何时从“数据”变为“无数据”,regardless of what protocol was used.
【解决方案2】:
myTelephonyManager=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

callStateListener = new PhoneStateListener(){
    public void onDataConnectionStateChanged(int state){
        switch(state){
        case TelephonyManager.DATA_DISCONNECTED:
            Log.i("State: ", "Offline");
            // String stateString = "Offline";
            // Toast.makeText(getApplicationContext(),
            // stateString, Toast.LENGTH_LONG).show();
            break;
        case TelephonyManager.DATA_SUSPENDED:
            Log.i("State: ", "IDLE");
            // stateString = "Idle";
            // Toast.makeText(getApplicationContext(),
            // stateString, Toast.LENGTH_LONG).show();
            break;
        }
    }       
};                      
myTelephonyManager.listen(callStateListener,
            PhoneStateListener.LISTEN_DATA_CONNECTION_STATE); 

【讨论】:

  • 注意:您可以通过再次调用listen并传递“LISTEN_NONE”来停止收听;见:groups.google.com/forum/?fromgroups=#!topic/android-beginners/…
  • TelephonyManager 如何与 Wifi 状态更新连接。这真的适用于 wifi 和其他 3g 互联网吗?
  • 这在我连接到 WiFi 的平板电脑上不起作用。当我更改为飞行模式时 - 我没有收到任何通知!
【解决方案3】:

接受的答案对我不起作用(我的平板电脑已连接到 WiFi - 没有 3G)。以下代码对我有用:

public class ConnectivityChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("*** Action: " + intent.getAction());
        if(intent.getAction().equalsIgnoreCase("android.net.conn.CONNECTIVITY_CHANGE")) {
            Toast.makeText(context, "Connection changed", Toast.LENGTH_SHORT).show();
        }
    }
}

以及对 AndroidManifest.xml 的更改

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

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

【讨论】:

    【解决方案4】:

    不确定这是否会有所帮助,但this looks similar...

    【讨论】:

    • 我认为这个问题类似,只是我想知道设备何时从“互联网连接”变为“无互联网连接”。它是在 WiFi 还是 3G 网络上对我来说并不重要。但会调查它。谢谢
    • 类似但不一样的问题。
    【解决方案5】:

    我通过轮询 ConnectivityManager 实现了这个功能。

    _connectivityManager = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
    

    一旦我们有了连接管理器,只需不时轮询它,看看您是否仍然连接

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    final Runnable networkStatusChecker = new Runnable() {
        public void run() {
            NetworkInfo activeNetwork = _connectivityManager.getActiveNetworkInfo();
            boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
            if(!isConnected) {
                System.out.println("disconnected from network");
                networkCheckerHandle.cancel(true);
            }
        }
    };
    final ScheduledFuture networkCheckerHandle = scheduler.scheduleAtFixedRate(networkStatusChecker, 10, 10, SECONDS);
    

    【讨论】:

    • 您为什么认为使用 ConnectivityManager.CONNECTIVITY_ACTION 需要 API 级别 21 或更高?根据docs,这是在 API 级别 1 中添加的。
    • 看来你是对的,不确定我从哪里得到 API 级别 21。谢谢指出
    【解决方案6】:

    如果你想在 Kotlin 中这样做。使用这个

       val isInternetWorking: Boolean by lazy {
            var success = false
            try {
                val url = URL("https://google.com")
                val connection = url.openConnection() as HttpURLConnection
                connection.connectTimeout = 10000
                connection.connect()
                success = connection.responseCode === 200
            } catch (e: IOException) {
                e.printStackTrace()
            }
    
            return@lazy success
        }
    

    在一个线程中执行此操作。

    【讨论】:

      【解决方案7】:

      您可以轻松使用 Merlin 和他的胡须。在这里您还可以获得一种连接类型:移动或 wifi。

      implementation 'com.novoda:merlin:1.2.0'
      
      private MerlinsBeard merlinsBeard;
      
      private NetworkChecker(Context context){
      
          Merlin merlin = new Merlin.Builder()
                  .withConnectableCallbacks()
                  .withDisconnectableCallbacks()
                  .build(context);
      
          merlinsBeard = new MerlinsBeard.Builder().build(context);
      
          merlin.registerConnectable(() -> {
              Timber.d("Connection enabled");
          });
      
          merlin.registerDisconnectable(() -> {
              Timber.d("Connection disabled");
          });
      
          merlin.bind();
      }
      
      
      public boolean getConnected(){
          return merlinsBeard.isConnected();
      }
      

      【讨论】:

      • 我想检查互联网是否已连接,然后共享首选项用于此目的我该怎么做我是新手,我不知道有关它的所有方法和程序
      猜你喜欢
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 2022-01-09
      • 2014-04-19
      • 1970-01-01
      • 2014-07-29
      • 2019-12-05
      • 2017-06-29
      相关资源
      最近更新 更多