如何監(jiān)測Android網(wǎng)絡(luò)類型:5G/4G/3G/2G能力
App可以通過了解所連接的網(wǎng)絡(luò)類型來獲益,例如啟用某些功能需要5G提供的帶寬和低延遲。如果只有2G或3G網(wǎng)絡(luò)可用,加載時間會比較慢,因此我們可以對加載時間有一定的預(yù)期。
在這里,我們可以利用TelephonyManager類來獲取各種關(guān)于移動網(wǎng)絡(luò)狀態(tài)的信息,其中包括網(wǎng)絡(luò)類型!不過,使用TelephonyManager相當(dāng)復(fù)雜,因為不同的Android版本有不同的情況需要考慮。
下面我提供了一個示例應(yīng)用程序,它可以檢測我們所連接的移動網(wǎng)絡(luò)類型,不僅僅是5G / 4G / 3G / 2G,還可以獲取到具體的子類型。該應(yīng)用使用了TelephonyManager,并結(jié)合了Jetpack Compose、ViewModel和Kotlin Flow的編寫方式。
使用TelephonyManager注冊以接收網(wǎng)絡(luò)信息更新
獲取TelephonyManager的方法如下:
valtelephonyManager= context.getSystemService(Context.TELEPHONY_SERVICE)asTelephonyManager
...當(dāng)上下文是一個Context實例時。請注意,一些手機具有多個SIM卡;如果您想查詢特定的SIM卡,請調(diào)用TelephonyManager實例上的.createForSubscriptionId(simCardNumber)。
使用這個實例,我們現(xiàn)在可以獲取網(wǎng)絡(luò)信息更新。所使用的過程取決于Android版本,即用戶的Android版本,而不是您應(yīng)用的目標(biāo)API級別。
Android ≥ 12(API ≥ 31)
Android 12及更高版本是最簡單的情況,因為有一個專用的監(jiān)聽器,并且不需要權(quán)限。
要注冊接收網(wǎng)絡(luò)類型信息,我們使用registerTelephonyCallback(Executor, TelephonyCallback)方法,如下所示:
//ThethreadExecutorusedtorunthelistener.Thisgovernshowthreadsarecreatedand //reused.Hereweuseasinglethread. valexec=Executors.newSingleThreadExecutor() //Createthecallbackobject valcallback=object:TelephonyCallback(),TelephonyCallback.DisplayInfoListener{ overridefunonDisplayInfoChanged(telephonyDisplayInfo:TelephonyDisplayInfo){ //TODO:Thisisnext } } //Finally,registerthecallbacksoitcanstartreceivingresults. telephonyManager.registerTelephonyCallback(exec,callback)
注銷監(jiān)聽器,方法如下:
telephonyManager.unregisterTelephonyCallback(callback)
"""
僅限 Android 11 (API 30)
注冊電話管理器回調(diào)的原始方法是使用 listen 方法。該方法接受各種類型的監(jiān)聽器;我們需要的是實現(xiàn)onDisplayInfoChanged接口的監(jiān)聽器。
有趣的是,這個方法在一個 Android 版本中就出現(xiàn)并消失了:
這需要READ_PHONE_STATE權(quán)限。我們將在 UI 代碼中稍后處理?,F(xiàn)在我們將繼續(xù),假定我們已經(jīng)擁有該權(quán)限。
//(Atthetopofthefile) @file:Suppress("DEPRECATION")//Suppressedasrequiredtosupportoldversion //SDK30usesTelephonyManager.listen()tolistenforTelephonyDisplayInfochanges. //ItrequiresREAD_PHONE_STATEpermission. @Suppress("OVERRIDE_DEPRECATION")//Suppressedasrequiredtosupportoldversion //Thisistheobjectthatwillreceivetheresults valcallback=object:PhoneStateListener(exec){ overridefunonDisplayInfoChanged(telephonyDisplayInfo:TelephonyDisplayInfo){ //TODO:Thisisnext } } //Startlisteningforresults telephonyManager.listen(callback,PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
注銷監(jiān)聽使用下面代碼:
telephonyManager.listen(callback,0)
Android ≥ 7(API ≥ 24)
Android 10及以下沒有任何監(jiān)聽網(wǎng)絡(luò)類型變化的方法。要支持較舊的版本,您需要實施一個循環(huán),每隔幾秒主動檢查。
檢查的代碼如下:
valnetworkType=telephonyManager.dataNetworkType
這需要READ_PHONE_STATE權(quán)限。
請注意,Android 10及以下版本不能支持5G,因為5G僅在Android 11及以上版本中可用。
返回的值:網(wǎng)絡(luò)類型常量
在上述 Android 11 和 ≥12 的代碼中,會收到一個帶有TelephonyDisplayInfo對象的回調(diào)。該對象包含一個networkType和一個overrideNetworkType。而在 Android ≤10 的代碼中,只會收到一個networkType。
無論哪種情況,networkType可以是以下之一:
valbaseTypeString=when(networkType){ TelephonyManager.NETWORK_TYPE_CDMA->"CDMA" TelephonyManager.NETWORK_TYPE_1xRTT->"1xRTT" TelephonyManager.NETWORK_TYPE_EDGE->"EDGE" TelephonyManager.NETWORK_TYPE_EHRPD->"eHRPD" TelephonyManager.NETWORK_TYPE_EVDO_0->"EVDOrev0" TelephonyManager.NETWORK_TYPE_EVDO_A->"EVDOrevA" TelephonyManager.NETWORK_TYPE_EVDO_B->"EVDOrevB" TelephonyManager.NETWORK_TYPE_GPRS->"GPRS" TelephonyManager.NETWORK_TYPE_GSM->"GSM" TelephonyManager.NETWORK_TYPE_HSDPA->"HSDPA" TelephonyManager.NETWORK_TYPE_HSPA->"HSPA" TelephonyManager.NETWORK_TYPE_HSPAP->"HSPA+" TelephonyManager.NETWORK_TYPE_HSUPA->"HSUPA" TelephonyManager.NETWORK_TYPE_IDEN->"iDen" TelephonyManager.NETWORK_TYPE_IWLAN->"IWLAN" TelephonyManager.NETWORK_TYPE_LTE->"LTE" TelephonyManager.NETWORK_TYPE_NR->"NR(newradio)5G" TelephonyManager.NETWORK_TYPE_TD_SCDMA->"TD_SCDMA" TelephonyManager.NETWORK_TYPE_UMTS->"UMTS" else->"[Unknown]" }
如果可用,overrideNetworkType會為某些類型的4G和5G連接提供更多信息。以下是選項:
valoverrideString=when(overrideNetworkType){ TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA->"5Gnon-standalone" TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED->"5Gstandalone(advanced)" TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO->"LTEAdvancedPro(5Ge)" TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA->"LTE(carrieraggregation)" else->null }
可能的null處理:
valnetTypeString=overrideString?:baseTypeString
將其構(gòu)建為一個Kotlin + Flows + ViewModel + Compose應(yīng)用程序
我在ViewModel中使用了一個KotlincallbackFlow來設(shè)置上述監(jiān)聽器。如果您以前沒有遇到過callbackFlow,那就太棒了:它是一個流,可用于在外部API上創(chuàng)建一個監(jiān)聽器,當(dāng)有人注冊時,自動移除該監(jiān)聽器。
我使用.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)將callbackFlow從冷可觀察對象轉(zhuǎn)換為共享熱可觀察對象。這樣,如果有多個消費者注冊,就不會創(chuàng)建多個DisplayInfoListeners或PhoneStateListeners。WhileSubscribed(5000)部分確保可觀察對象在所有消費者消失后仍保持存在一段時間,以防它們即將重新出現(xiàn)。(例如,在屏幕旋轉(zhuǎn)的情況下會發(fā)生這種情況)。
在Composable中,我使用collectAsStateWithLifecycle()來確保監(jiān)聽器僅在應(yīng)用程序位于前臺時處于活動狀態(tài)。
審核編輯:劉清
-
Android
+關(guān)注
關(guān)注
12文章
3917瀏覽量
127040 -
移動網(wǎng)絡(luò)
+關(guān)注
關(guān)注
2文章
443瀏覽量
32794
原文標(biāo)題:如何監(jiān)測Android網(wǎng)絡(luò)類型:5G/4G/3G/2G能力
文章出處:【微信號:哆啦安全,微信公眾號:哆啦安全】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論