android-不推荐使用ConnectivityManager.CONNECTIVITY_ACTION
在Android N中,官方网站上提到“针对Android N的应用不会收到CONNECTIVITY_ACTION广播”。 并且还提到可以将CONNECTING用作替代方案。 但是CONNECTED不能提供与CONNECTIVITY_ACTION广播完全相同的行为。
在我的Android应用程序中,我正在使用此广播来了解设备的网络状态。 我想知道此状态是CONNECTING还是CONNECTED,在CONNECTIVITY_ACTION广播的帮助下,它最适合我的要求。
现在已经过时了,有人可以建议我获取当前网络状态的另一种方法吗?
Raghuram db asked 2019-10-08T17:53:46Z
7个解决方案
69 votes
不推荐使用后台应用程序接收网络连接状态更改的功能。
正如David Wasser所说,如果实例化(未销毁)应用程序组件并且您已经以编程方式将接收者与其上下文进行了注册,而不是在清单中进行操作,则仍会收到有关连接更改的通知。
或者,您可以改用NetworkCallback。 特别是,您将需要重写onAvailable来更改连接状态。
让我快速起草一个摘要:
public class ConnectionStateMonitor extends NetworkCallback {
final NetworkRequest networkRequest;
public ConnectionStateMonitor() {
networkRequest = new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
}
public void enable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.registerNetworkCallback(networkRequest , this);
}
// Likewise, you can have a disable method that simply calls ConnectivityManager.unregisterNetworkCallback(NetworkCallback) too.
@Override
public void onAvailable(Network network) {
// Do what you need to do here
}
}
Amokrane Chentir answered 2019-10-08T17:54:17Z
21 votes
Android N的文档指出:
定位到Android N的应用没有收到CONNECTIVITY_ACTION 广播,即使它们具有清单条目以请求通知 这些事件中。 在前台运行的应用仍然可以收听 如果他们请求通知,则在其主线程上进行CONNECTIVITY_CHANGE 与BroadcastReceiver。
这意味着,如果您的应用程序在前台运行,您仍然可以注册BroadcastReceiver,以检测网络连接的变化。
David Wasser answered 2019-10-08T17:54:55Z
11 votes
我将更新Sayem's以获得修复棉绒问题的答案,该问题将向我显示。
class ConnectionLiveData(val context: Context) : LiveData() {
private var connectivityManager: ConnectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback
override fun onActive() {
super.onActive()
updateConnection()
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityManagerCallback())
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> lollipopNetworkAvailableRequest()
else -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
context.registerReceiver(networkReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")) // android.net.ConnectivityManager.CONNECTIVITY_ACTION
}
}
}
}
override fun onInactive() {
super.onInactive()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
} else {
context.unregisterReceiver(networkReceiver)
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun lollipopNetworkAvailableRequest() {
val builder = NetworkRequest.Builder()
.addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)
connectivityManager.registerNetworkCallback(builder.build(), getConnectivityManagerCallback())
}
private fun getConnectivityManagerCallback(): ConnectivityManager.NetworkCallback {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network?) {
postValue(true)
}
override fun onLost(network: Network?) {
postValue(false)
}
}
return connectivityManagerCallback
} else {
throw IllegalAccessError("Should not happened")
}
}
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
updateConnection()
}
}
private fun updateConnection() {
val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
postValue(activeNetwork?.isConnected == true)
}
}
和相同的用法:
val connectionLiveData = ConnectionLiveData(context)
connectionLiveData.observe(this, Observer { isConnected ->
isConnected?.let {
// do job
}
})
顺便说一句,感谢您的解决方案。
Kebab Krabby answered 2019-10-08T17:55:33Z
8 votes
请先检查@Amokrane Chentir答案以获取android N支持。
对于那些想在所有api级别上支持并在ui中进行观察的人,请检查以下代码。
NetworkConnection的LiveData:
class ConnectionLiveData(val context: Context) : LiveData(){
var intentFilter = IntentFilter(CONNECTIVITY_ACTION)
private var connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
private lateinit var networkCallback : NetworkCallback
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
networkCallback = NetworkCallback(this)
}
}
override fun onActive() {
super.onActive()
updateConnection()
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(networkCallback)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
val builder = NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
else -> {
context.registerReceiver(networkReceiver, intentFilter)
}
}
}
override fun onInactive() {
super.onInactive()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.unregisterNetworkCallback(networkCallback)
} else{
context.unregisterReceiver(networkReceiver)
}
}
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
updateConnection()
}
}
fun updateConnection() {
val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
postValue(activeNetwork?.isConnectedOrConnecting == true)
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class NetworkCallback(val liveData : ConnectionLiveData) : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network?) {
liveData.postValue(true)
}
override fun onLost(network: Network?) {
liveData.postValue(false)
}
}
}
在UI中观察(活动/片段):
val connectionLiveData = ConnectionLiveData(context)
connectionLiveData.observe(this, Observer {
// do whatever you want with network connectivity change
})
Sayem answered 2019-10-08T17:56:17Z
7 votes
几天前,我遇到了同样的问题,因此决定使用这个库Android-Job
该库使用JobSchedular、GcmNetworkManager和BroadcastReceiver,具体取决于运行该应用的Android版本。
找工作很容易
new JobRequest.Builder(DemoSyncJob.TAG)
.setRequiresCharging(true)
.setRequiresDeviceIdle(false)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) // this is what gets the job done
.build()
.schedule();
Noman Rafique answered 2019-10-08T17:56:56Z
2 votes
定位到Android N(牛轧糖)的应用不会收到清单中定义的setRequiredNetworkType()广播(请参见Svelte)。
可能的解决方案:
一旦应用程序运行,就使用setRequiredNetworkType()显式注册网络回调。
使用setRequiredNetworkType(),并通过setRequiredNetworkType()指定未计量的网络。
另请参阅Android O-在后台检测连接性更改
rds answered 2019-10-08T17:57:50Z
0 votes
我同意@rds建议的答案。
请记住,API级别28不推荐使用CONNECTIVITY_ACTION。
如果您有要求,尽管存在以下问题,则应检测到Wifi状态(连接/断开连接) 应用被杀死,您想定位最新版本,那么您 没有太多选择。
您需要使用connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
问题是您不能使用BroadcastReceiver,那怎么办?
您可以使用JobScheduler,也可以使用WorkManager(定期请求)更好的服务。 为什么选择周期性,因为如果它是一个OneTimeRequest,则它将只能运行一次并在您的应用程序处于前台时继续监听。
文档说:
回调将继续被调用,直到应用程序退出或链接#unregisterNetworkCallback(NetworkCallback)}被调用为止。
一旦应用被终止或从最近的应用列表中删除,networkCallback将无法收听。
因此,您需要进行此类定期工作以使应用程序不断进行监听。 持续时间应该是多少? 这取决于您,取决于具体情况。
我知道这有点丑陋,但这就是事实。 一个挑战可能是,如果用户的设备处于打ze模式或应用程序处于待机状态,则您的工作可能会延迟。
Wahib Ul Haq answered 2019-10-08T17:59:24Z