ConnectivityManager.CONNECTIVITY_ACTION 지원 중단됨
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
}
}
Android N에 대한 문서는 다음과 같이 설명합니다.
Android N을 타겟팅하는 앱은 이러한 이벤트 알림을 요청하는 매니페스트 항목이 있더라도 CONNECTIVITY_ACTION 브로드 캐스트를 수신하지 않습니다. 포 그라운드에서 실행되는 앱은 BroadcastReceiver로 알림을 요청하는 경우 기본 스레드에서 CONNECTIVITY_CHANGE를 계속 수신 할 수 있습니다.
즉 BroadcastReceiver
, 네트워크 연결의 변경 사항을 감지하기 위해 앱이 포 그라운드에서 실행중인 경우를 계속 등록 할 수 있습니다 .
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
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
}
})
Btw 당신의 solusion에 대한 sayem 감사합니다.
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();
안드로이드 N (누가)를 대상으로 앱은받지 않습니다 CONNECTIVITY_ACTION
(참조 매니페스트에 정의 된 방송을 벨테을 ).
가능한 해결책:
ConnectivityManager.registernetworkCallback()
애플리케이션이 실행되면 네트워크 콜백을 명시 적으로 등록합니다 .- 를 사용하고
JobScheduler
를 통해 무제한 네트워크를 지정합니다setRequiredNetworkType()
.
Android O-백그라운드에서 연결 변경 감지를 참조하십시오.
@rds가 제안한 답변에 동의합니다 .
것을 명심 마십시오 CONNECTIVITY_ACTION는 API 레벨 28에서 더 이상 사용되지 않습니다.
앱이 종료 되었음에도 불구하고 Wifi 상태 (연결 / 연결 해제)를 감지해야한다는 요구 사항이 있고 최신 버전을 대상으로 지정하려는 경우 선택의 여지가별로 없습니다.
당신은 사용해야합니다 connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
질문은 BroadcastReceiver를 사용할 수 없다는 것입니다.
WorkManager (Periodic Request) 인 경우 JobScheduler 이상을 사용할 수 있습니다. OneTimeRequest 인 경우 한 번만 실행할 수 있고 앱이 포 그라운드에있는 동안 계속 수신 할 수 있기 때문에 왜 주기적입니다.
문서 내용 :
콜백은 애플리케이션이 종료되거나 링크 #unregisterNetworkCallback (NetworkCallback)}이 호출 될 때까지 계속 호출됩니다.
앱이 종료되거나 최근 앱 목록에서 제거되면 networkCallback이들을 수 없습니다.
따라서 앱이 지속적으로 수신하도록하려면 이러한주기적인 작업이 필요합니다. 기간은 얼마입니까? 그것은 당신에게 달려 있으며 경우에 따라 다릅니다.
나는 그것이 약간 추한 방법이라는 것을 알고 있지만 이것이 방법입니다. 한 가지 문제는 사용자의 기기가 잠자기 모드에 있거나 앱이 대기 상태에있는 경우 작업이 지연 될 수 있다는 것입니다.
나는 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" />
도움이되는 의견과 개선 사항을 기다리겠습니다.
참고 URL : https://stackoverflow.com/questions/36421930/connectivitymanager-connectivity-action-deprecated
'developer tip' 카테고리의 다른 글
dup2 / dup-파일 설명자를 복제해야하는 이유는 무엇입니까? (0) | 2020.10.22 |
---|---|
gcc 옵션 -fomit-frame-pointer 이해하기 (0) | 2020.10.22 |
목록에서 가장 오래된 / 가장 어린 datetime 개체 찾기 (0) | 2020.10.21 |
파이썬에서 두 목록을 사전으로 결합하려면 어떻게해야합니까? (0) | 2020.10.21 |
각도에서 module.config (configFn)에 종속성을 주입하는 방법 (0) | 2020.10.21 |