英文:
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_WIFI
和TRANSPORT_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_INTERNET
和NET_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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论