activeNetworkInfo.type 在 API 级别 28 中已弃用
activeNetworkInfo.type is deprecated in API level 28
我想使用提供方法 activeNetworkInfo.type 的连接管理器来检查 Android 中的网络类型。此方法在 API 级别 28 中已弃用。那么在 API 28 中检查网络类型的解决方案是什么。我的代码是:
/**
* Check Wi Fi connectivity
*/
fun isWiFiConnected(context: Context): Boolean {
val connManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return connManager.activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI
}
我的 Gradle 就像:
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
}
更新
The connectivityManager.activeNetworkInfo
is also deprecated in API level 29
现在我们需要使用ConnectivityManager.NetworkCallback API
or ConnectivityManager#getNetworkCapabilities or ConnectivityManager#getLinkProperties
SAMPLE CODE USING ConnectivityManager#getNetworkCapabilities
private fun isInternetAvailable(context: Context): Boolean {
var result = false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw =
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
result = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.run {
connectivityManager.activeNetworkInfo?.run {
result = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return result
}
旧答案
Yes getType()
is deprecated in API level 28
现在我们需要使用 Callers should switch to checking NetworkCapabilities.hasTransport(int)
还有 getAllNetworkInfo()
is deprecated in API level 29
现在我们需要使用 getAllNetworks()
instead of getNetworkInfo(android.net.Network)
.
getNetworkInfo()
- Returns 有关特定网络的连接状态信息。
getAllNetworks()
- Returns 框架当前跟踪的所有网络的数组。
示例代码
fun isWiFiConnected(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
} else {
connectivityManager.activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI
}
}
完整代码
@Suppress("DEPRECATION")
fun isInternetAvailable(context: Context): Boolean {
var result = false
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cm?.run {
cm.getNetworkCapabilities(cm.activeNetwork)?.run {
result = when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
}
}
} else {
cm?.run {
cm.activeNetworkInfo?.run {
if (type == ConnectivityManager.TYPE_WIFI) {
result = true
} else if (type == ConnectivityManager.TYPE_MOBILE) {
result = true
}
}
}
}
return result
}
没有,从这里看:https://developer.android.com/reference/android/net/ConnectivityManager.html#getActiveNetworkInfo()
getActiveNetworkInfo()
在 Android API 28 中仍然可用,并且没有任何地方说它已被弃用。
但是弃用的是 NetworkInfo getType()
class。
https://developer.android.com/reference/android/net/NetworkInfo#getType()
This method was deprecated in API level 28.
Callers should switch to checking
NetworkCapabilities.hasTransport(int)
instead with one of the
NetworkCapabilities#TRANSPORT_* constants : getType()
and
getTypeName()
cannot account for networks using multiple transports.
Note that generally apps should not care about transport;
NetworkCapabilities.NET_CAPABILITY_NOT_METERED
and
NetworkCapabilities.getLinkDownstreamBandwidthKbps()
are calls that
apps concerned with meteredness or bandwidth should be looking at, as
they offer this information with much better accuracy.
我根据自己的需要改编了 Nilesh Rathod 的回答:
enum class ConnectivityMode {
NONE,
WIFI,
MOBILE,
OTHER,
MAYBE
}
var connectivityMode = ConnectivityMode.NONE
private fun checkConnectivity(context: Context): ConnectivityMode {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
cm?.run {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getNetworkCapabilities(activeNetwork)?.run {
return when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> ConnectivityMode.WIFI
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> ConnectivityMode.MOBILE
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> ConnectivityMode.OTHER
hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> ConnectivityMode.MAYBE
else -> ConnectivityMode.NONE
}
}
} else {
@Suppress("DEPRECATION")
activeNetworkInfo?.run {
return when (type) {
ConnectivityManager.TYPE_WIFI -> ConnectivityMode.WIFI
ConnectivityManager.TYPE_MOBILE -> ConnectivityMode.MOBILE
ConnectivityManager.TYPE_ETHERNET -> ConnectivityMode.OTHER
ConnectivityManager.TYPE_BLUETOOTH -> ConnectivityMode.MAYBE
else -> ConnectivityMode.NONE
}
}
}
}
return ConnectivityMode.NONE
}
然后我用okhttp检查连接:
fun updateData(manual: Boolean, windowContext: Context) = runBlocking {
connectivityMode = checkConnectivity(MyApplication.context)
if (connectivityMode != ConnectivityMode.NONE) {
val conn : Boolean = GlobalScope.async {
var retval = false
try {
val request = Request.Builder().url(WORK_URL).build()
val response = client.newCall(request).execute()
Log.i(TAG, "code = ${response?.code}")
if (response?.code == 200) {
// I use the response body since it is a small file and already downloaded
val input = response.body?.byteStream()
if (input != null) {
// do stuff
response.body?.close()
retval = true
}
}
}
catch(exception: Exception) {
Log.e(TAG, "error ${exception.message ?: ""}")
}
retval
}.await()
if (!conn) {
connectivityMode = ConnectivityMode.NONE
}
}
....
如果您使用 min API 级别 23,则可以使用这个缩短的 Kotlin 版本。
fun isNetworkAvailable(context: Context): Boolean {
(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).apply {
return getNetworkCapabilities(activeNetwork)?.run {
when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} ?: false
}
}
最近我不得不编写一个小函数来检查我的单个 WebView 中的网络连接。我还注意到 API 发生了很大的变化,尤其是当 Kotlin 出现时,找到有效参考花了几分钟时间。
这是我的小 NetworkConnectivityManager
class,具有检查网络可用性的简单功能。
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
class NetworkConnectivityManager(context: Context) {
private val connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
@Suppress("DEPRECATION")
fun isNetworkAvailable(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val nc = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
nc != null
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
}
这是我针对 SDK 29 的解决方案:一个名为 NetworkWatcher
的 class,它观察网络的变化。它提供原始变量,例如 isWifiOn
以及通过 Flow and LiveData.
观察网络随时间变化的选项
@ExperimentalCoroutinesApi
class NetworkWatcher
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
private constructor(
application: Application
) {
private val connectivityManager =
application.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
// general availability of Internet over any type
var isOnline = false
get() {
updateFields()
return field
}
var isOverWifi = false
get() {
updateFields()
return field
}
var isOverCellular = false
get() {
updateFields()
return field
}
var isOverEthernet = false
get() {
updateFields()
return field
}
companion object {
@Volatile
private var INSTANCE: NetworkWatcher? = null
fun getInstance(application: Application): NetworkWatcher {
synchronized(this) {
if (INSTANCE == null) {
INSTANCE = NetworkWatcher(application)
}
return INSTANCE!!
}
}
}
@Suppress("DEPRECATION")
private fun updateFields() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkAvailability =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (networkAvailability != null &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
) {
//has network
isOnline = true
// wifi
isOverWifi =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
// cellular
isOverCellular =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
// ethernet
isOverEthernet =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
} else {
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
}
} else {
val info = connectivityManager.activeNetworkInfo
if (info != null && info.isConnected) {
isOnline = true
val wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
isOverWifi = wifi != null && wifi.isConnected
val cellular = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
isOverCellular = cellular != null && cellular.isConnected
val ethernet = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET)
isOverEthernet = ethernet != null && ethernet.isConnected
} else {
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
}
}
}
fun watchNetwork(): Flow<Boolean> = watchWifi()
.combine(watchCellular()) { wifi, cellular -> wifi || cellular }
.combine(watchEthernet()) { wifiAndCellular, ethernet -> wifiAndCellular || ethernet }
fun watchNetworkAsLiveData(): LiveData<Boolean> = watchNetwork().asLiveData()
fun watchWifi(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_WIFI)
fun watchWifiAsLiveData() = watchWifi().asLiveData()
fun watchCellular(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_CELLULAR)
fun watchCellularAsLiveData() = watchCellular().asLiveData()
fun watchEthernet(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_ETHERNET)
fun watchEthernetAsLiveData() = watchEthernet().asLiveData()
private fun callbackFlowForType(@IntRange(from = 0, to = 7) type: Int) = callbackFlow {
offer(false)
val networkRequest = NetworkRequest.Builder()
.addTransportType(type)
.build()
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onLost(network: Network?) {
offer(false)
}
override fun onUnavailable() {
offer(false)
}
override fun onLosing(network: Network?, maxMsToLive: Int) {
// do nothing
}
override fun onAvailable(network: Network?) {
offer(true)
}
}
connectivityManager.registerNetworkCallback(networkRequest, callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
}
例如,您可以在您的应用程序中订阅有关 phone 网络状态的更新,例如:
GlobalScope.launch {
NetworkWatcher.getInstance(this@MyApplication).watchNetwork().collect { connected ->
Log.d("TAG", "Network In App: $connected")
}
}
或者要回答您的问题,只需读取 Wifi 值,例如:
if (NetworkWatcher.getInstance(this@BaseApp).isOverWifi) {
// do stuff
}
旁注:我没有一直使用 getInstance()
,而是使用 Koin 等 DI 框架在我需要的地方注入 NetworkWatcher。
Java代码:
public static boolean isConnectingToInternet(Context mContext) {
if (mContext == null) return false;
ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final Network network = connectivityManager.getActiveNetwork();
if (network != null) {
final NetworkCapabilities nc = connectivityManager.getNetworkCapabilities(network);
return (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
}
} else {
NetworkInfo[] networkInfos = connectivityManager.getAllNetworkInfo();
for (NetworkInfo tempNetworkInfo : networkInfos) {
if (tempNetworkInfo.isConnected()) {
return true;
}
}
}
}
return false;
}
我只是想知道,如果设备连接到互联网,无论连接类型如何:
@Suppress("DEPRECATION")
fun isOnline(context: Context?): Boolean {
var connected = false
@Suppress("LiftReturnOrAssignment")
context?.let {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = cm.activeNetwork ?: return false
val actNw = cm.getNetworkCapabilities(networkCapabilities) ?: return false
connected = actNw.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
} else {
val netInfo = cm.activeNetworkInfo
connected = netInfo?.isConnectedOrConnecting == true
}
}
return connected
}
我正在使用这个 Kotlin 函数来检查互联网连接:
Be careful about version checking (Version >= M)
private fun isInternetConnected():Boolean{
val connectivityManager = this.getSystemService(android.content.Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val activeNetwork = connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
return when {
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ||
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
else -> false
}
}
else {
return connectivityManager.activeNetworkInfo != null &&
connectivityManager.activeNetworkInfo!!.isConnectedOrConnecting
}
}
稍微简单的版本(minSdkVersion 23+)
fun isNetworkAvailable(context: Context) =
(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).run {
getNetworkCapabilities(activeNetwork)?.run {
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
} ?: false
}
希望这对您有用!
此代码在 api 21 之后有效
// 创建一个新的 class 并添加以下
public class CheckNetwork {
public static boolean isNetworkConnected;
private Context context;
public CheckNetwork(Context context) {
this.context = context;
}
public boolean isOnline(){
isNetworkConnected = false;
ConnectivityManager connectivityMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] allNetworks = connectivityMgr.getAllNetworks(); // added in API 21 (Lollipop)
for (Network network : allNetworks) {
NetworkCapabilities networkCapabilities = connectivityMgr.getNetworkCapabilities(network);
if (networkCapabilities != null) {
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
isNetworkConnected = true;
}
}
return isNetworkConnected;
}
}
// 在 MainActivity
CheckNetwork myNetwork = new CheckNetwork(this);
//在OnCreateMethod
myNetwork.isOnline();
if (myNetwork.isNetworkConnected){
Toast.makeText(this, "Please check your Internet Connection", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "Your Internet Connction is Ok", Toast.LENGTH_SHORT).show();
}
这是两种方法的 Kotlin 实现 old/new api:
@Suppress("DEPRECATION")
fun isConnectedOld(context: Context): Boolean {
val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = connManager.activeNetworkInfo
return networkInfo.isConnected
}
@RequiresApi(Build.VERSION_CODES.M)
fun isConnectedNewApi(context: Context): Boolean {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
return capabilities?.hasCapability(NET_CAPABILITY_INTERNET) == true
}
和常用方法:
fun isConnected(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
isConnectedNewApi(context)
} else{
isConnectedOld(context)
}
}
完整的解决方案
在包中创建这些 class 让我们说 connectivity
- 接口 ConnectivityProvider
进口android.content.Context
导入 android.content.Context.CONNECTIVITY_SERVICE
导入 android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkInfo
import android.os.Build
import androidx.annotation.RequiresApi
interface ConnectivityProvider {
interface ConnectivityStateListener {
fun onStateChange(state: NetworkState)
}
fun addListener(listener: ConnectivityStateListener)
fun removeListener(listener: ConnectivityStateListener)
fun getNetworkState(): NetworkState
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
sealed class NetworkState {
object NotConnectedState : NetworkState()
sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
capabilities.hasCapability(NET_CAPABILITY_INTERNET)
)
@Suppress("DEPRECATION")
data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
networkInfo.isConnectedOrConnecting
)
}
}
companion object {
fun createProvider(context: Context): ConnectivityProvider {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ConnectivityProviderImpl(cm)
} else {
ConnectivityProviderLegacyImpl(context, cm)
}
}
}
}
摘要classConnectivityProviderBaseImpl
abstract class ConnectivityProviderBaseImpl : ConnectivityProvider {
private val handler = Handler(Looper.getMainLooper())
private val listeners = mutableSetOf<ConnectivityStateListener>()
private var subscribed = false
override fun addListener(listener: ConnectivityStateListener) {
listeners.add(listener)
listener.onStateChange(getNetworkState()) // propagate an initial state
verifySubscription()
}
override fun removeListener(listener: ConnectivityStateListener) {
listeners.remove(listener)
verifySubscription()
}
private fun verifySubscription() {
if (!subscribed && listeners.isNotEmpty()) {
subscribe()
subscribed = true
} else if (subscribed && listeners.isEmpty()) {
unsubscribe()
subscribed = false
}
}
protected fun dispatchChange(state: NetworkState) {
handler.post {
for (listener in listeners) {
listener.onStateChange(state)
}
}
}
protected abstract fun subscribe()
protected abstract fun unsubscribe()
}
class ConnectivityProviderImpl
@RequiresApi(Build.VERSION_CODES.N)
class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
ConnectivityProviderBaseImpl() {
private val networkCallback = ConnectivityCallback()
override fun subscribe() {
cm.registerDefaultNetworkCallback(networkCallback)
}
override fun unsubscribe() {
cm.unregisterNetworkCallback(networkCallback)
}
override fun getNetworkState(): NetworkState {
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
return if (capabilities != null) {
Connected(capabilities)
} else {
NotConnectedState
}
}
private inner class ConnectivityCallback : NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
dispatchChange(Connected(capabilities))
}
override fun onLost(network: Network) {
dispatchChange(NotConnectedState)
}
}
}
- class ConnectivityProviderLegacyImpl
@Suppress("弃用")
class ConnectivityProviderLegacyImpl(
private val context: Context,
private val cm: ConnectivityManager
) : ConnectivityProviderBaseImpl() {
private val receiver = ConnectivityReceiver()
override fun subscribe() {
context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
}
override fun unsubscribe() {
context.unregisterReceiver(receiver)
}
override fun getNetworkState(): NetworkState {
val activeNetworkInfo = cm.activeNetworkInfo
return if (activeNetworkInfo != null) {
ConnectedLegacy(activeNetworkInfo)
} else {
NotConnectedState
}
}
private inner class ConnectivityReceiver : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
// on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
// https://issuetracker.google.com/issues/37137911
val networkInfo = cm.activeNetworkInfo
val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
// a set of dirty workarounds
val state: NetworkState =
if (networkInfo?.isConnectedOrConnecting == true) {
ConnectedLegacy(networkInfo)
} else if (networkInfo != null && fallbackNetworkInfo != null &&
networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
) {
ConnectedLegacy(fallbackNetworkInfo)
} else {
val state = networkInfo ?: fallbackNetworkInfo
if (state != null) ConnectedLegacy(state) else NotConnectedState
}
dispatchChange(state)
}
}
}
用法:- 首页Activity
class HomeActivity : BaseActivity(), ConnectivityProvider.ConnectivityStateListener {
val provider: ConnectivityProvider by lazy { ConnectivityProvider.createProvider(this@HomeActivity) }
override fun onStart() {
super.onStart()
provider.addListener(this)
}
override fun onStop() {
super.onStop()
provider.removeListener(this)
}
override fun onStateChange(state: ConnectivityProvider.NetworkState) {
val hasInternet = state.hasInternet()
}
companion object {
fun ConnectivityProvider.NetworkState.hasInternet(): Boolean {
return (this as? ConnectivityProvider.NetworkState.ConnectedState)?.hasInternet == true
}
}
单击按钮或任何 api 调用
if(provider.getNetworkState().hasInternet()){
// do work
}
}
如果您想在家庭活动片段中使用互联网
if ((activity as HomeActivity).provider.getNetworkState().hasInternet()) {
// api call
}
版本 >= Build.VERSION_CODES.M
:
private fun isConnected(context: Context): Boolean {
val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
val capabilities = manager?.getNetworkCapabilities(manager.activeNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
}
在 Kotlin 中,您可以检查 Android 版本,并根据版本检查连接管理器。
fun Context.isInternetAvailable(): Boolean {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
val cap = cm.getNetworkCapabilities(cm.activeNetwork) ?: return false
return cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
val networks = cm.allNetworks
for (n in networks) {
val nInfo = cm.getNetworkInfo(n)
if (nInfo != null && nInfo.isConnected) return true
}
}
else -> {
val networks = cm.allNetworkInfo
for (nInfo in networks) {
if (nInfo != null && nInfo.isConnected) return true
}
}
}
return false
}
调用你的扩展函数activity
if (applicationContext.isInternetAvailable()) { }
这就是我所做的。在“if 语句”的第一部分,我检查用户是否正在使用 android 的新版本,在第二部分,我对旧的 Android SDK 使用 AciveNetworkInfo。
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
//return depending on the version in the last version of API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork ?: return false
val activeNetwork =
connectivityManager.getNetworkCapabilities(network) ?: return false
return when {
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ->true
else -> false
}
} else {
//for the old version of android sdk we use follow code
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnectedOrConnecting
}
}
/**
* Check Wi Fi connectivity
*/
fun isWiFiConnected(context: Context): Boolean {
val connManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return connManager.activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI
}
我的 Gradle 就像:
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
}
更新
The connectivityManager.activeNetworkInfo
is also deprecated in API level 29
现在我们需要使用ConnectivityManager.NetworkCallback API
or ConnectivityManager#getNetworkCapabilities or ConnectivityManager#getLinkProperties
SAMPLE CODE USING
ConnectivityManager#getNetworkCapabilities
private fun isInternetAvailable(context: Context): Boolean {
var result = false
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw =
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
result = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.run {
connectivityManager.activeNetworkInfo?.run {
result = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return result
}
旧答案
Yes getType()
is deprecated in API level 28
现在我们需要使用 Callers should switch to checking NetworkCapabilities.hasTransport(int)
还有 getAllNetworkInfo()
is deprecated in API level 29
现在我们需要使用 getAllNetworks()
instead of getNetworkInfo(android.net.Network)
.
getNetworkInfo()
- Returns 有关特定网络的连接状态信息。
getAllNetworks()
- Returns 框架当前跟踪的所有网络的数组。
示例代码
fun isWiFiConnected(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
} else {
connectivityManager.activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI
}
}
完整代码
@Suppress("DEPRECATION")
fun isInternetAvailable(context: Context): Boolean {
var result = false
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
cm?.run {
cm.getNetworkCapabilities(cm.activeNetwork)?.run {
result = when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
}
}
} else {
cm?.run {
cm.activeNetworkInfo?.run {
if (type == ConnectivityManager.TYPE_WIFI) {
result = true
} else if (type == ConnectivityManager.TYPE_MOBILE) {
result = true
}
}
}
}
return result
}
没有,从这里看:https://developer.android.com/reference/android/net/ConnectivityManager.html#getActiveNetworkInfo()
getActiveNetworkInfo()
在 Android API 28 中仍然可用,并且没有任何地方说它已被弃用。
但是弃用的是 NetworkInfo getType()
class。
https://developer.android.com/reference/android/net/NetworkInfo#getType()
This method was deprecated in API level 28.
Callers should switch to checking
NetworkCapabilities.hasTransport(int)
instead with one of theNetworkCapabilities#TRANSPORT_* constants : getType()
andgetTypeName()
cannot account for networks using multiple transports. Note that generally apps should not care about transport;NetworkCapabilities.NET_CAPABILITY_NOT_METERED
andNetworkCapabilities.getLinkDownstreamBandwidthKbps()
are calls that apps concerned with meteredness or bandwidth should be looking at, as they offer this information with much better accuracy.
我根据自己的需要改编了 Nilesh Rathod 的回答:
enum class ConnectivityMode {
NONE,
WIFI,
MOBILE,
OTHER,
MAYBE
}
var connectivityMode = ConnectivityMode.NONE
private fun checkConnectivity(context: Context): ConnectivityMode {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
cm?.run {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getNetworkCapabilities(activeNetwork)?.run {
return when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> ConnectivityMode.WIFI
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> ConnectivityMode.MOBILE
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> ConnectivityMode.OTHER
hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> ConnectivityMode.MAYBE
else -> ConnectivityMode.NONE
}
}
} else {
@Suppress("DEPRECATION")
activeNetworkInfo?.run {
return when (type) {
ConnectivityManager.TYPE_WIFI -> ConnectivityMode.WIFI
ConnectivityManager.TYPE_MOBILE -> ConnectivityMode.MOBILE
ConnectivityManager.TYPE_ETHERNET -> ConnectivityMode.OTHER
ConnectivityManager.TYPE_BLUETOOTH -> ConnectivityMode.MAYBE
else -> ConnectivityMode.NONE
}
}
}
}
return ConnectivityMode.NONE
}
然后我用okhttp检查连接:
fun updateData(manual: Boolean, windowContext: Context) = runBlocking {
connectivityMode = checkConnectivity(MyApplication.context)
if (connectivityMode != ConnectivityMode.NONE) {
val conn : Boolean = GlobalScope.async {
var retval = false
try {
val request = Request.Builder().url(WORK_URL).build()
val response = client.newCall(request).execute()
Log.i(TAG, "code = ${response?.code}")
if (response?.code == 200) {
// I use the response body since it is a small file and already downloaded
val input = response.body?.byteStream()
if (input != null) {
// do stuff
response.body?.close()
retval = true
}
}
}
catch(exception: Exception) {
Log.e(TAG, "error ${exception.message ?: ""}")
}
retval
}.await()
if (!conn) {
connectivityMode = ConnectivityMode.NONE
}
}
....
如果您使用 min API 级别 23,则可以使用这个缩短的 Kotlin 版本。
fun isNetworkAvailable(context: Context): Boolean {
(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).apply {
return getNetworkCapabilities(activeNetwork)?.run {
when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} ?: false
}
}
最近我不得不编写一个小函数来检查我的单个 WebView 中的网络连接。我还注意到 API 发生了很大的变化,尤其是当 Kotlin 出现时,找到有效参考花了几分钟时间。
这是我的小 NetworkConnectivityManager
class,具有检查网络可用性的简单功能。
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
class NetworkConnectivityManager(context: Context) {
private val connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
@Suppress("DEPRECATION")
fun isNetworkAvailable(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val nc = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
nc != null
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnected
}
}
这是我针对 SDK 29 的解决方案:一个名为 NetworkWatcher
的 class,它观察网络的变化。它提供原始变量,例如 isWifiOn
以及通过 Flow and LiveData.
@ExperimentalCoroutinesApi
class NetworkWatcher
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
private constructor(
application: Application
) {
private val connectivityManager =
application.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
// general availability of Internet over any type
var isOnline = false
get() {
updateFields()
return field
}
var isOverWifi = false
get() {
updateFields()
return field
}
var isOverCellular = false
get() {
updateFields()
return field
}
var isOverEthernet = false
get() {
updateFields()
return field
}
companion object {
@Volatile
private var INSTANCE: NetworkWatcher? = null
fun getInstance(application: Application): NetworkWatcher {
synchronized(this) {
if (INSTANCE == null) {
INSTANCE = NetworkWatcher(application)
}
return INSTANCE!!
}
}
}
@Suppress("DEPRECATION")
private fun updateFields() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkAvailability =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (networkAvailability != null &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
) {
//has network
isOnline = true
// wifi
isOverWifi =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
// cellular
isOverCellular =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
// ethernet
isOverEthernet =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
} else {
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
}
} else {
val info = connectivityManager.activeNetworkInfo
if (info != null && info.isConnected) {
isOnline = true
val wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
isOverWifi = wifi != null && wifi.isConnected
val cellular = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
isOverCellular = cellular != null && cellular.isConnected
val ethernet = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET)
isOverEthernet = ethernet != null && ethernet.isConnected
} else {
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
}
}
}
fun watchNetwork(): Flow<Boolean> = watchWifi()
.combine(watchCellular()) { wifi, cellular -> wifi || cellular }
.combine(watchEthernet()) { wifiAndCellular, ethernet -> wifiAndCellular || ethernet }
fun watchNetworkAsLiveData(): LiveData<Boolean> = watchNetwork().asLiveData()
fun watchWifi(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_WIFI)
fun watchWifiAsLiveData() = watchWifi().asLiveData()
fun watchCellular(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_CELLULAR)
fun watchCellularAsLiveData() = watchCellular().asLiveData()
fun watchEthernet(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_ETHERNET)
fun watchEthernetAsLiveData() = watchEthernet().asLiveData()
private fun callbackFlowForType(@IntRange(from = 0, to = 7) type: Int) = callbackFlow {
offer(false)
val networkRequest = NetworkRequest.Builder()
.addTransportType(type)
.build()
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onLost(network: Network?) {
offer(false)
}
override fun onUnavailable() {
offer(false)
}
override fun onLosing(network: Network?, maxMsToLive: Int) {
// do nothing
}
override fun onAvailable(network: Network?) {
offer(true)
}
}
connectivityManager.registerNetworkCallback(networkRequest, callback)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}
}
例如,您可以在您的应用程序中订阅有关 phone 网络状态的更新,例如:
GlobalScope.launch {
NetworkWatcher.getInstance(this@MyApplication).watchNetwork().collect { connected ->
Log.d("TAG", "Network In App: $connected")
}
}
或者要回答您的问题,只需读取 Wifi 值,例如:
if (NetworkWatcher.getInstance(this@BaseApp).isOverWifi) {
// do stuff
}
旁注:我没有一直使用 getInstance()
,而是使用 Koin 等 DI 框架在我需要的地方注入 NetworkWatcher。
Java代码:
public static boolean isConnectingToInternet(Context mContext) {
if (mContext == null) return false;
ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final Network network = connectivityManager.getActiveNetwork();
if (network != null) {
final NetworkCapabilities nc = connectivityManager.getNetworkCapabilities(network);
return (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
}
} else {
NetworkInfo[] networkInfos = connectivityManager.getAllNetworkInfo();
for (NetworkInfo tempNetworkInfo : networkInfos) {
if (tempNetworkInfo.isConnected()) {
return true;
}
}
}
}
return false;
}
我只是想知道,如果设备连接到互联网,无论连接类型如何:
@Suppress("DEPRECATION")
fun isOnline(context: Context?): Boolean {
var connected = false
@Suppress("LiftReturnOrAssignment")
context?.let {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = cm.activeNetwork ?: return false
val actNw = cm.getNetworkCapabilities(networkCapabilities) ?: return false
connected = actNw.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
} else {
val netInfo = cm.activeNetworkInfo
connected = netInfo?.isConnectedOrConnecting == true
}
}
return connected
}
我正在使用这个 Kotlin 函数来检查互联网连接:
Be careful about version checking (Version >= M)
private fun isInternetConnected():Boolean{
val connectivityManager = this.getSystemService(android.content.Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val activeNetwork = connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
return when {
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ||
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
else -> false
}
}
else {
return connectivityManager.activeNetworkInfo != null &&
connectivityManager.activeNetworkInfo!!.isConnectedOrConnecting
}
}
稍微简单的版本(minSdkVersion 23+)
fun isNetworkAvailable(context: Context) =
(context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).run {
getNetworkCapabilities(activeNetwork)?.run {
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
} ?: false
}
希望这对您有用! 此代码在 api 21 之后有效
// 创建一个新的 class 并添加以下
public class CheckNetwork {
public static boolean isNetworkConnected;
private Context context;
public CheckNetwork(Context context) {
this.context = context;
}
public boolean isOnline(){
isNetworkConnected = false;
ConnectivityManager connectivityMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] allNetworks = connectivityMgr.getAllNetworks(); // added in API 21 (Lollipop)
for (Network network : allNetworks) {
NetworkCapabilities networkCapabilities = connectivityMgr.getNetworkCapabilities(network);
if (networkCapabilities != null) {
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
isNetworkConnected = true;
}
}
return isNetworkConnected;
}
}
// 在 MainActivity
CheckNetwork myNetwork = new CheckNetwork(this);
//在OnCreateMethod
myNetwork.isOnline();
if (myNetwork.isNetworkConnected){
Toast.makeText(this, "Please check your Internet Connection", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "Your Internet Connction is Ok", Toast.LENGTH_SHORT).show();
}
这是两种方法的 Kotlin 实现 old/new api:
@Suppress("DEPRECATION")
fun isConnectedOld(context: Context): Boolean {
val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = connManager.activeNetworkInfo
return networkInfo.isConnected
}
@RequiresApi(Build.VERSION_CODES.M)
fun isConnectedNewApi(context: Context): Boolean {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
return capabilities?.hasCapability(NET_CAPABILITY_INTERNET) == true
}
和常用方法:
fun isConnected(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
isConnectedNewApi(context)
} else{
isConnectedOld(context)
}
}
完整的解决方案 在包中创建这些 class 让我们说 connectivity
- 接口 ConnectivityProvider
进口android.content.Context 导入 android.content.Context.CONNECTIVITY_SERVICE 导入 android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkInfo
import android.os.Build
import androidx.annotation.RequiresApi
interface ConnectivityProvider {
interface ConnectivityStateListener {
fun onStateChange(state: NetworkState)
}
fun addListener(listener: ConnectivityStateListener)
fun removeListener(listener: ConnectivityStateListener)
fun getNetworkState(): NetworkState
@Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
sealed class NetworkState {
object NotConnectedState : NetworkState()
sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
capabilities.hasCapability(NET_CAPABILITY_INTERNET)
)
@Suppress("DEPRECATION")
data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
networkInfo.isConnectedOrConnecting
)
}
}
companion object {
fun createProvider(context: Context): ConnectivityProvider {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ConnectivityProviderImpl(cm)
} else {
ConnectivityProviderLegacyImpl(context, cm)
}
}
}
}
摘要class
ConnectivityProviderBaseImpl
abstract class ConnectivityProviderBaseImpl : ConnectivityProvider { private val handler = Handler(Looper.getMainLooper()) private val listeners = mutableSetOf<ConnectivityStateListener>() private var subscribed = false override fun addListener(listener: ConnectivityStateListener) { listeners.add(listener) listener.onStateChange(getNetworkState()) // propagate an initial state verifySubscription() } override fun removeListener(listener: ConnectivityStateListener) { listeners.remove(listener) verifySubscription() } private fun verifySubscription() { if (!subscribed && listeners.isNotEmpty()) { subscribe() subscribed = true } else if (subscribed && listeners.isEmpty()) { unsubscribe() subscribed = false } } protected fun dispatchChange(state: NetworkState) { handler.post { for (listener in listeners) { listener.onStateChange(state) } } } protected abstract fun subscribe() protected abstract fun unsubscribe()
}
class ConnectivityProviderImpl
@RequiresApi(Build.VERSION_CODES.N)
class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
ConnectivityProviderBaseImpl() {
private val networkCallback = ConnectivityCallback()
override fun subscribe() {
cm.registerDefaultNetworkCallback(networkCallback)
}
override fun unsubscribe() {
cm.unregisterNetworkCallback(networkCallback)
}
override fun getNetworkState(): NetworkState {
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
return if (capabilities != null) {
Connected(capabilities)
} else {
NotConnectedState
}
}
private inner class ConnectivityCallback : NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
dispatchChange(Connected(capabilities))
}
override fun onLost(network: Network) {
dispatchChange(NotConnectedState)
}
}
}
- class ConnectivityProviderLegacyImpl
@Suppress("弃用")
class ConnectivityProviderLegacyImpl(
private val context: Context,
private val cm: ConnectivityManager
) : ConnectivityProviderBaseImpl() {
private val receiver = ConnectivityReceiver()
override fun subscribe() {
context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
}
override fun unsubscribe() {
context.unregisterReceiver(receiver)
}
override fun getNetworkState(): NetworkState {
val activeNetworkInfo = cm.activeNetworkInfo
return if (activeNetworkInfo != null) {
ConnectedLegacy(activeNetworkInfo)
} else {
NotConnectedState
}
}
private inner class ConnectivityReceiver : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
// on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
// https://issuetracker.google.com/issues/37137911
val networkInfo = cm.activeNetworkInfo
val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
// a set of dirty workarounds
val state: NetworkState =
if (networkInfo?.isConnectedOrConnecting == true) {
ConnectedLegacy(networkInfo)
} else if (networkInfo != null && fallbackNetworkInfo != null &&
networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
) {
ConnectedLegacy(fallbackNetworkInfo)
} else {
val state = networkInfo ?: fallbackNetworkInfo
if (state != null) ConnectedLegacy(state) else NotConnectedState
}
dispatchChange(state)
}
}
}
用法:- 首页Activity
class HomeActivity : BaseActivity(), ConnectivityProvider.ConnectivityStateListener {
val provider: ConnectivityProvider by lazy { ConnectivityProvider.createProvider(this@HomeActivity) }
override fun onStart() {
super.onStart()
provider.addListener(this)
}
override fun onStop() {
super.onStop()
provider.removeListener(this)
}
override fun onStateChange(state: ConnectivityProvider.NetworkState) {
val hasInternet = state.hasInternet()
}
companion object {
fun ConnectivityProvider.NetworkState.hasInternet(): Boolean {
return (this as? ConnectivityProvider.NetworkState.ConnectedState)?.hasInternet == true
}
}
单击按钮或任何 api 调用
if(provider.getNetworkState().hasInternet()){
// do work
}
}
如果您想在家庭活动片段中使用互联网
if ((activity as HomeActivity).provider.getNetworkState().hasInternet()) {
// api call
}
版本 >= Build.VERSION_CODES.M
:
private fun isConnected(context: Context): Boolean {
val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
val capabilities = manager?.getNetworkCapabilities(manager.activeNetwork) ?: return false
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
}
在 Kotlin 中,您可以检查 Android 版本,并根据版本检查连接管理器。
fun Context.isInternetAvailable(): Boolean {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
val cap = cm.getNetworkCapabilities(cm.activeNetwork) ?: return false
return cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
val networks = cm.allNetworks
for (n in networks) {
val nInfo = cm.getNetworkInfo(n)
if (nInfo != null && nInfo.isConnected) return true
}
}
else -> {
val networks = cm.allNetworkInfo
for (nInfo in networks) {
if (nInfo != null && nInfo.isConnected) return true
}
}
}
return false
}
调用你的扩展函数activity
if (applicationContext.isInternetAvailable()) { }
这就是我所做的。在“if 语句”的第一部分,我检查用户是否正在使用 android 的新版本,在第二部分,我对旧的 Android SDK 使用 AciveNetworkInfo。
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
//return depending on the version in the last version of API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork ?: return false
val activeNetwork =
connectivityManager.getNetworkCapabilities(network) ?: return false
return when {
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ->true
else -> false
}
} else {
//for the old version of android sdk we use follow code
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo != null && networkInfo.isConnectedOrConnecting
}
}