【问题标题】:How to observe network change in real time如何实时观察网络变化
【发布时间】:2022-06-01 23:53:43
【问题描述】:

你好我有一个简单的应用程序我所做的是当用户在启动应用程序时没有连接到互联网时它会显示一个文本视图“没有互联网”但问题是当我启动互联网或连接到任何网络时它没有显示原始视图我要做的是关闭应用程序并再次打开以显示主视图

当连接打开/关闭时,如何在这两个视图之间实时切换

创建

  // Internet on/off
        if (isOnline()) {
            noInternet.setVisibility(View.INVISIBLE); // Online
            mainRelativeLayout.setVisibility(View.VISIBLE);

        } else {
            noInternet.setVisibility(View.VISIBLE); // Disconnected
            mainRelativeLayout.setVisibility(View.INVISIBLE);
        }

这就是我目前正在使用的获取连接信息

 // Internet on/off
    public boolean isOnline() {
        boolean connected = false;
        try {
            ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            connected = networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected();
            return connected;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connected;
    }
  • 您想要观察连接变化并相应地改变您的视图吗?
  • 是的,正确,这就是我想要的
  • 太好了,我会在几分钟内回答这个问题。

标签: java android broadcastreceiver android-view


【解决方案1】:

要实时观察连接变化,您可以使用 LiveData。在此之前我们使用了 BroadcastReceiver,但正如您所见 Declaring a broadcastreceiver for android.net.conn.CONNECTIVITY_CHANGE is deprecated for apps targeting N and higher.

我将发布完整的代码并解释它的每一部分。

public class ConnectionLiveData extends LiveData<Boolean> {
    private ConnectivityManager.NetworkCallback networkCallback;
    private final ConnectivityManager cm;
    private final HashSet<Network> validNetworks = new HashSet<>();
    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    public static final int NETWORK_STATUS_POST_DELAY = 1000;

 public ConnectionLiveData(Context context) {
        cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

private void checkValidNetworks() {
    new Handler(Looper.getMainLooper()).postDelayed(() ->
                    postValue(validNetworks.size() > 0),
            NETWORK_STATUS_POST_DELAY);
}

@Override
protected void onActive() {
    networkCallback = createNetworkCallback();
    NetworkRequest networkRequest = new NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build();
    cm.registerNetworkCallback(networkRequest, networkCallback);
}

@Override
protected void onInactive() {
    cm.unregisterNetworkCallback(networkCallback);
}

private ConnectivityManager.NetworkCallback createNetworkCallback() {
    return new ConnectivityManager.NetworkCallback() {
        /*
        Called when a network is detected. If that network has internet, save it in the Set.
        Source: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onAvailable(android.net.Network)
        */
        @Override
        public void onAvailable(@NonNull Network network) {
            NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
            boolean hasInternetCapability = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
            if (hasInternetCapability) {
                // check if this network actually has internet
                executor.execute(() -> {
                    boolean hasInternet = DoesNetworkHaveInternet.execute(network.getSocketFactory());
                    if (hasInternet) {
                        validNetworks.add(network);
                        checkValidNetworks();
                    }
                });
            }
        }

        /*
        If the callback was registered with registerNetworkCallback() it will be called for each network which no longer satisfies the criteria of the callback.
        Source: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onLost(android.net.Network)
        */
        @Override
        public void onLost(@NonNull Network network) {
            validNetworks.remove(network);
            checkValidNetworks();
        }
    };
}

}

我们在这里扩展LiveData 并实现两个功能:onActive()onInactive()。如您所知,LiveData 是生命周期感知的,当有一个观察者时,onActive 将被调用。我用它们来注册/注销ConnectivityManager。 当我们注册 ConnectivityManager 时,我们将 networkCallback 作为参数传递。它有几种方法,但正如您在 createNetworkCallback() 函数中看到的那样,我们仅覆盖 onAvailable()onLost() 函数。如果您要打开/关闭网络,将调用 onAvailable()onLost()

可能存在连接打开但与服务器没有连接的情况。在这种情况下,我找到了一个简单的类,我们可以使用它来 ping 和验证我们的连接。 使用ExecutorService 我通过ping 验证互联网连接。

boolean hasInternet = DoesNetworkHaveInternet.execute(network.getSocketFactory());

DoesNetworkHaveInternet 代码:

public class DoesNetworkHaveInternet {

private static final String HOST_NAME = "8.8.8.8";
private static final int PORT = 53;
private static final int CONNECT_TIMEOUT = 1500;

@WorkerThread
static Boolean execute(SocketFactory socketFactory) {
    try {
        Socket socket = socketFactory.createSocket();
        socket.connect(new InetSocketAddress(HOST_NAME, PORT), CONNECT_TIMEOUT);
        socket.close();
        return true;
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}
}

它正在 ping 并验证我们有稳定的连接。 最后,在验证我们有连接之后,我们调用checkValidNetworks() 函数。有延迟,因为在某些情况下,您的连接可能会暂时关闭和打开,为此我发现没有必要显示网络错误。 checkValidNetworks() 检查validNetworks 是否不为空。这是一个列表,因为存在某些类型的连接,例如 wifi 和移动网络。如果至少有一个稳定的连接,validNetworks 不会为空。 而已。您可以在您的片段或这样的活动中观察它:

ConnectionLiveDataJava connectionLiveData = new ConnectionLiveDataJava(this);
connectionLiveData.observe(this, isConnected -> {
            
});

【讨论】:

  • 嘿,谢谢你的代码,但它的 kotlin ,请你能分享一下 java 代码吗
  • 对不起,我没有它的Java版本。你能尝试将代码从 kotlin 翻译成 Java 吗?
  • 我不明白你要我做什么
  • @Player91 我已将代码从 Kotlin 更新为 Java。祝你好运 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 2010-12-01
  • 1970-01-01
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多