Android N에서는 공식 웹 사이트에 “Android N을 대상으로하는 앱은 CONNECTIVITY_ACTION 방송을 수신하지 않습니다”라고 언급되어 있습니다. 그리고 JobScheduler
대안으로 사용할 수있는 것도 언급 됩니다. 그러나는 방송 JobScheduler
과 똑같은 동작을 제공하지 않습니다 CONNECTIVITY_ACTION
.
내 Android 애플리케이션에서이 브로드 캐스트를 사용하여 장치의 네트워크 상태를 알고있었습니다. 나는이 상태가 있다면 알고 싶어 CONNECTING
하거나 CONNECTED
의 도움으로 CONNECTIVITY_ACTION
방송과 가장 잘 내 요구 사항에 적합했다.
이제 더 이상 사용되지 않으므로 현재 네트워크 상태를 가져 오는 대체 방법을 제안 할 수 있습니까?
답변
더 이상 사용되지 않는 것은 백그라운드 애플리케이션이 네트워크 연결 상태 변경을 수신하는 기능입니다.
로 데이비드 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
}
}
답변
Sayem's
린트 문제 해결에 대한 답변을 업데이트 하겠습니다.
class ConnectionLiveData(val context: Context) : LiveData<Boolean>() {
private var connectivityManager: ConnectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback
private val networkRequestBuilder: NetworkRequest.Builder = NetworkRequest.Builder()
.addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)
override fun onActive() {
super.onActive()
updateConnection()
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityMarshmallowManagerCallback())
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> marshmallowNetworkAvailableRequest()
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() {
connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityLollipopManagerCallback())
}
@TargetApi(Build.VERSION_CODES.M)
private fun marshmallowNetworkAvailableRequest() {
connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityMarshmallowManagerCallback())
}
private fun getConnectivityLollipopManagerCallback(): 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("Accessing wrong API version")
}
}
private fun getConnectivityMarshmallowManagerCallback(): ConnectivityManager.NetworkCallback {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network?, networkCapabilities: NetworkCapabilities?) {
networkCapabilities?.let { capabilities ->
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
postValue(true)
}
}
}
override fun onLost(network: Network?) {
postValue(false)
}
}
return connectivityManagerCallback
} else {
throw IllegalAccessError("Accessing wrong API version")
}
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
}
})
Btw 귀하의 솔루션에 대해 sayem에게 감사드립니다.
답변
Android N에 대한 문서는 다음과 같이 설명합니다.
Android N을 타겟팅하는 앱은 이러한 이벤트 알림을 요청하는 매니페스트 항목이 있더라도 CONNECTIVITY_ACTION 브로드 캐스트를 수신하지 않습니다. 포 그라운드에서 실행되는 앱은 BroadcastReceiver로 알림을 요청하는 경우 기본 스레드에서 CONNECTIVITY_CHANGE를 계속 수신 할 수 있습니다.
즉 BroadcastReceiver
, 네트워크 연결의 변경 사항을 감지하기 위해 앱이 포 그라운드에서 실행중인 경우를 계속 등록 할 수 있습니다 .
답변
Android N 지원에 대한 첫 번째 @Amokrane Chentir 답변을 확인하십시오.
모든 API 레벨에서 지원하고 UI에서 관찰하고 싶은 분들은 아래 코드를 확인 해주세요.
NetworkConnection의 LiveData :
class ConnectionLiveData(val context: Context) : LiveData<Boolean>(){
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
})
답변
며칠 전 같은 문제가 발생하여 Android-Job 라이브러리를 사용하기로 결정했습니다.
이 라이브러리 용도 JobSchedular
, GcmNetworkManager
그리고 BroadcastReceiver
어떤 안드로이드 버전에 따라 응용 프로그램에서 실행 중입니다.
일을 시작하는 것은 상당히 쉽습니다
new JobRequest.Builder(DemoSyncJob.TAG)
.setRequiresCharging(true)
.setRequiresDeviceIdle(false)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) // this is what gets the job done
.build()
.schedule();
답변
나는 Sayam의 답변을 기반으로 하지만 LiveData
. ConnectivityManager#registerDefaultNetworkCallback
Android Nougat를 대상으로하는 최신 API 메서드 ( ) 를 호출하기로 결정했습니다 .
/**
* Observes network connectivity by consulting the [ConnectivityManager].
* Observing can run infinitely or automatically be stopped after the first response is received.
*/
class ConnectivityObserver @JvmOverloads constructor(
val context: Context,
val onConnectionAvailable: () -> Unit,
val onConnectionLost: () -> Unit = {},
val shouldStopAfterFirstResponse: Boolean = false
) {
private val connectivityManager
get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
@Suppress("DEPRECATION")
private val intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
private val broadCastReceiver = object : BroadcastReceiver() {
@Suppress("DEPRECATION")
override fun onReceive(context: Context?, intent: Intent?) {
if (ConnectivityManager.CONNECTIVITY_ACTION != intent?.action) {
return
}
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnectedOrConnecting) {
onConnectionAvailable.invoke()
} else {
onConnectionLost.invoke()
}
if (shouldStopAfterFirstResponse) {
stop()
}
}
}
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
onConnectionAvailable.invoke()
if (shouldStopAfterFirstResponse) {
stop()
}
}
override fun onLost(network: Network?) {
super.onLost(network)
onConnectionLost.invoke()
if (shouldStopAfterFirstResponse) {
stop()
}
}
}
}
}
fun start() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
// Decouple from component lifecycle, use application context.
// See: https://developer.android.com/reference/android/content/Context.html#getApplicationContext()
context.applicationContext.registerReceiver(broadCastReceiver, intentFilter)
} else {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
}
}
fun stop() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
context.applicationContext.unregisterReceiver(broadCastReceiver)
} else {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
}
용법:
val onConnectionAvailable = TODO()
val connectivityObserver = ConnectivityObserver(context, onConnectionAvailable)
connectivityObserver.start()
connectivityObserver.stop()
또는:
val onConnectionAvailable = TODO()
val onConnectionLost = TODO()
ConnectivityObserver(context,
onConnectionAvailable,
onConnectionLost,
shouldStopAfterFirstResponse = true
).start()
AndroidManifest.xml에ACCESS_NETWORK_STATE
권한 을 추가하는 것을 잊지 마십시오 .
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
도움이되는 의견과 개선 사항을 기다리겠습니다.
답변
@KebabKrabby의 답변을 바탕으로 :
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.ConnectivityManager.EXTRA_NO_CONNECTIVITY
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.os.Build
import androidx.lifecycle.LiveData
class ConnectivityWatcher(
private val context: Context
): LiveData<Boolean>() {
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
private lateinit var broadcastReceiver: BroadcastReceiver
override fun onActive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
networkCallback = createNetworkCallback()
cm.registerDefaultNetworkCallback(networkCallback)
} else {
val intentFilter = IntentFilter(CONNECTIVITY_ACTION)
broadcastReceiver = createBroadcastReceiver()
context.registerReceiver(broadcastReceiver, intentFilter)
}
}
override fun onInactive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
cm.unregisterNetworkCallback(networkCallback)
} else {
context.unregisterReceiver(broadcastReceiver)
}
}
private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
val isInternet = networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)
val isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)
postValue(isInternet && isValidated)
}
override fun onLost(network: Network) {
postValue(false)
}
}
private fun createBroadcastReceiver() = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isNoConnectivity = intent?.extras?.getBoolean(EXTRA_NO_CONNECTIVITY) ?: true
postValue(!isNoConnectivity)
}
}
}
그리고 그것을 사용하는 것은 원래 답변과 거의 동일합니다 (예를 들어 활동에서 관찰하는 경우).
ConnectivityWatcher(this).observe(this, Observer {
Log.i("*-*-*", "is internet available? - ${if (it) "Yes" else "No"}")
})