ConnectivityManager的回调在BlueStacks 5模拟器中不起作用。

huangapple go评论67阅读模式
英文:

Callback for ConnectivityManager not working in BlueStacks 5 emulator

问题

为了在设备连接/断开互联网时收到通知,我采用了以下方法:

ConnectivityManager connectivityManager = activity.getSystemService(ConnectivityManager.class);

ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(@NonNull Network network) {
        super.onAvailable(network);
        try {
            activity.runOnUiThread(() -> {
                tvNoInternet.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        MiscellaneousUtils.hideView(tvNoInternet, View.GONE);
                    }
                });
                behaviour.onConnected();
                // behaviour is an interface named NetworkConnectionBehaviour (check the following snippet for its implementation)
            });
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onLost(@NonNull Network network) {
        super.onLost(network);
        try {
            activity.runOnUiThread(() -> {
                if (isInternetConnected(activity)) {
                    // check internet connection status because onLost() is called
                    // after onAvailable() when the device automatically switches
                    // internet connection from cellular to wifi
                    return;
                }
                tvNoInternet.animate().alpha(1f).setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        super.onAnimationStart(animation);
                        MiscellaneousUtils.showView(tvNoInternet);
                    }
                });
                behaviour.onDisconnected();
            });
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }
};

try {
    NetworkRequest networkRequest = getNetworkRequest();
    // implementation of getNetworkRequest() is added in the next snippet
    connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
} catch (Exception e) {
    Toast.makeText(activity, "Unexpected interruption! please try again later", Toast.LENGTH_SHORT).show();
}

接口 NetowrkConnectionBehaviour

public interface NetworkConnectionBehaviour {
    void onConnected();

    void onDisconnected();
}

getNetworkRequest() 的实现:

public static NetworkRequest getNetworkRequest() {
    return new NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
            .build();
}

这种方法在所有物理设备和 Android Studio 的模拟器上都能正常工作。

但是,如果有人在 Bluestacks 5 模拟器上运行该应用程序,ConnectivityManager 的回调根本不会被调用,也不会产生任何异常。

我是否漏掉了什么?在 BlueStacks 上使用 ConnectivityManager 有不同的方法吗?

注意:对于 gameloop 模拟器也显示相同的行为。

英文:

In order to get notified when the device connects/disconnects from internet, I took the following approach:

        ConnectivityManager connectivityManager = activity.getSystemService(ConnectivityManager.class);

        ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(@NonNull Network network) {
                super.onAvailable(network);
                try {
                    activity.runOnUiThread(() -> {
                        tvNoInternet.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                MiscellaneousUtils.hideView(tvNoInternet, View.GONE);
                            }
                        });
                        behaviour.onConnected();
                        // behaviour is an interface named NetworkConnectionBehaviour (check the following snippet for its implementation)
                    });
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onLost(@NonNull Network network) {
                super.onLost(network);
                try {
                    activity.runOnUiThread(() -> {
                        if (isInternetConnected(activity)) {
                            // check internet connection status because onLost() is called
                            // after onAvailable() when the device automatically switches
                            // internet connection from cellular to wifi
                            return;
                        }
                        tvNoInternet.animate().alpha(1f).setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationStart(Animator animation) {
                                super.onAnimationStart(animation);
                                MiscellaneousUtils.showView(tvNoInternet);
                            }
                        });
                        behaviour.onDisconnected();
                    });
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                }
            }
        };

        try {
            NetworkRequest networkRequest = getNetworkRequest(); 
            // implementation of getNetworkRequest() is added in next snippet
            connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
        } catch (Exception e) {
            Toast.makeText(activity, "Unexpected interruption! please try again later", Toast.LENGTH_SHORT).show();
        }

Interface NetowrkConnectionBehaviour:

    public interface NetworkConnectionBehaviour {
        void onConnected();

        void onDisconnected();
    }

Implementation of getNetworkRequest():

    public static NetworkRequest getNetworkRequest() {
        return new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .build();
    }

This approach is working in all physical devices and emulator of android studio.

However, if someone runs the app on Bluestacks 5 emulator, the callbacks of ConnectivityManager aren't called at all. And it does not produce any exception either.

Am I missing something here? Is there a different way to use ConnectivityManager for BlueStacks?

NOTE: It shows same behaviour for gameloop emulator too.

答案1

得分: 1

解决方案是移除传输类型:TRANSPORT_WIFITRANSPORT_CELLULAR,因为BlueStacks 5模拟器无法识别其连接为这些传输类型之一。

能力NET_CAPABILITY_INTERNET将确保连接正常工作并具有互联网访问权限,根据文档

表示此网络应该能够访问互联网。

NetworkRequest的代码现在应该如下所示:

public static NetworkRequest getNetworkRequest() {
    return new NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .build();
}
英文:

The solution is to remove transport types: TRANSPORT_WIFI and TRANSPORT_CELLULAR since the BlueStacks 5 Emulator does not recognize its connection to be one of those transport types.

The capability NET_CAPABILITY_INTERNET will ensure that the connection is working and has access to the internet as per docs:

> Indicates that this network should be able to reach the internet.

The code for the NetworkRequest now should be as follows:

public static NetworkRequest getNetworkRequest() {
    return new NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .build();
}

答案2

得分: 1

为了在设备连接/断开互联网时获得通知,最好使用registerDefaultNetworkCallback而不仅仅使用registerNetworkCallback
"默认网络"指的是应用程序用于互联网连接的默认网络,根据文档。
https://developer.android.com/reference/android/net/ConnectivityManager

尝试

connectivityManager.registerDefaultNetworkCallback(networkCallback);

然后,您可以像您在问题中定义的那样使用回调。

而且,如果您想检查是否已连接,您应该同时检查NET_CAPABILITY_INTERNETNET_CAPABILITY_VALIDATED。因此,我使用以下方式进行连接检查。

val caps = mConnectivityManager.getNetworkCapabilities(network)
if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && 
            caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
    // 已连接
}
英文:

In order to get notified when the device connects/disconnects from internet, It's better to use registerDefaultNetworkCallback instead of just registerNetworkCallback.
The "default network" means application's default network used for internet connection. as per docs.
https://developer.android.com/reference/android/net/ConnectivityManager

Try

connectivityManager.registerDefaultNetworkCallback(networkCallback);

And you can use callback as you defined in the question.

AND also, if you want to check it's connected, you should check both NET_CAPABILITY_INTERNET AND NET_CAPABILITY_VALIDATED.
So I used connectivity check like below.

val caps = mConnectivityManager.getNetworkCapabilities(network)
if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
// connected
}

huangapple
  • 本文由 发表于 2023年2月14日 19:08:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75446944.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定