Android相關(guān)硬件信息的獲取方式整理匯總
最近需要做個項目,里面涉及到一些收集Android硬件信息,雖說項目還沒開始,但也不影響自己先事先準備起來.
檢測是手機還是平板
Android中沒有提供特定的方法來判斷設(shè)備是手機還是平板,只能通過別的方式來間接判斷,比如通過判斷屏幕尺寸
infoText.text = checkIsTablet() private fun checkIsTablet(): String { val metrics = resources.displayMetrics val widthInches = metrics.widthPixels / metrics.xdpi val heightInches = metrics.heightPixels / metrics.ydpi val diagonalInches = sqrt(widthInches.pow(2.0f) + heightInches.pow(2.0f)) return if (diagonalInches >= 7.0) { "手機還是平板:平板" } else { "手機還是平板:手機" } }
驗證一下,分別將這段代碼運行在一個手機模擬器上以及平板模擬器上,結(jié)果如下
判斷是否為折疊屏
其實在折疊屏沒出現(xiàn)的時候,判斷手機或者是平板使用上述方法還是夠用的,但是在折疊屏面前就顯得信心不足了,折疊屏一展開,那就是一個長著平板臉的手機,為了識別折疊屏,Android10出來了一個新的感應(yīng)器類型TYPE_HINGE_ANGLE
,可以通過是否存在這種感應(yīng)器來識別折疊屏
private fun checkIsFoldScreen(): String { val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val hingeAngleSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE) return if (hingeAngleSensor == null) { "是否折疊屏:否" } else { "是否折疊屏: 是" } }
裝了一個折疊屏的模擬器,拿來試一下看看能不能識別
如果說想要具體拿到折疊屏的狀態(tài),比如是全展開還是半展開,或者收起狀態(tài),就要使用Jetpack WindowManager這個庫了,分別可以通過以下api拿到不同的狀態(tài)
不過這個得用真機試了,模擬器上拿不到FoldingFeature
,等我買了折疊屏再試下
屏幕密度與密度比例
這兩個值相信基本每個項目都會用到,屏幕密度一般用來判斷屏幕適配,加載不同的圖片資源,密度比例一般用來單位換算,這倆值都可以通過DisplayMetrics
來獲得
infoText.text = checkScreenDpiAndDensity() private fun checkScreenDpiAndDensity(): String { val displayMetric = resources.displayMetrics val dpi = displayMetric.densityDpi val density = displayMetric.density return "屏幕密度:${dpi} 密度比例:${density}" }
屏幕像素
private fun checkScreenPixel(): String { val displayMetrics = DisplayMetrics() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display?.getRealMetrics(displayMetrics) }else{ windowManager.defaultDisplay.getRealMetrics(displayMetrics); } val wPixel = displayMetrics.widthPixels val hPixel = displayMetrics.heightPixels return "像素(寬):${wPixel} 像素(高):${hPixel}" }
物理尺寸
物理尺寸在安卓上單位是英寸,它表示一個屏幕對角線的長度,至于如何計算對角線,就要用到上學(xué)時候用到的勾股定理,x,y分別是屏幕的寬高,注意的是由于單位是英寸,所以也要把上面計算出來的像素轉(zhuǎn)換成英寸,具體代碼如下
private fun checkPhysicalSize(): String { val displayMetrics = DisplayMetrics() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display?.getRealMetrics(displayMetrics) }else{ windowManager.defaultDisplay.getRealMetrics(displayMetrics); } val widthInches = displayMetrics.widthPixels / displayMetrics.xdpi val heightInches = displayMetrics.heightPixels / displayMetrics.ydpi val diagonalInches = sqrt( widthInches.pow(2.0f) + heightInches.pow(2.0f) ) return "物理尺寸 $diagonalInches" }
刷新率
刷新率一般就是指Android屏幕上每秒更新畫面的頻率,單位是赫茲,正常來講,普通設(shè)備的刷新率都為60赫茲,獲取刷新率的代碼如下
private fun checkRefreshRate(): String { val mDisplay = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display }else{ windowManager.defaultDisplay } return "刷新率 ${mDisplay?.refreshRate}" }
廣色域
有的設(shè)備支持廣色域,有的設(shè)備僅僅支持標準色域,廣色域的意思是屏幕可以顯示比標準色域(sRGB)更加豐富的顏色范圍,判斷一個設(shè)備是否支持廣色域的方式如下
private fun checkColorGamut(): String { val config: Configuration = resources.configuration if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val isWideColorGamut: Boolean = config.isScreenWideColorGamut val support = if(isWideColorGamut) "支持" else "不支持" return "是否支持廣色域模式:${support}" } return "不支持廣色域" }
獲取內(nèi)存(Runtime)
一般來講應(yīng)用想獲取內(nèi)存信息,用的最多的就是通過Runtime
來獲取,可以通過它獲取應(yīng)用最大可用內(nèi)存,當前分配的內(nèi)存,當前空閑內(nèi)存,已使用內(nèi)存
infoText.text = checkMemoryRuntime() private fun checkMemoryRuntime(): String { val runtime = Runtime.getRuntime() val maxMemory = runtime.maxMemory() // 應(yīng)用最大可用內(nèi)存 val totalMemory = runtime.totalMemory() // 當前分配的內(nèi)存 val freeMemory = runtime.freeMemory() // 當前空閑內(nèi)存 val usedMemory = totalMemory - freeMemory // 已使用內(nèi)存 return "最大可用內(nèi)存:${maxMemory} 當前分配的內(nèi)存:${totalMemory} 當前空閑內(nèi)存:${freeMemory} 已使用內(nèi)存${usedMemory}" }
獲取內(nèi)存(MemoryInfo)
還有一種方式就是通過獲取MemoryInfo來拿到內(nèi)存信息,比如總內(nèi)存,當前空閑內(nèi)存以及判斷內(nèi)存是否過低
infoText.text = checkMemoryMemoInfo() private fun checkMemoryMemoInfo(): String { val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val memoryInfo = ActivityManager.MemoryInfo() activityManager.getMemoryInfo(memoryInfo) val totalMem = memoryInfo.totalMem val availMem = memoryInfo.availMem val lowMemory = memoryInfo.lowMemory return "總內(nèi)存:${totalMem} 當前空閑內(nèi)存:${availMem} 內(nèi)存是否過低${lowMemory}" }
磁盤空間(外部存儲與內(nèi)部存儲)
可以通過StatFs
來獲取外部存儲以及內(nèi)存存儲容量
//外部存儲 infoText.text = checkExternalStorageInfo() private fun checkExternalStorageInfo(): String { if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) { val path = Environment.getExternalStorageDirectory() // 外部存儲根目錄 val stat = StatFs(path.path) val blockSize = stat.blockSizeLong val totalBlocks = stat.blockCountLong val availableBlocks = stat.availableBlocksLong val totalSize = blockSize * totalBlocks val availableSize = blockSize * availableBlocks val usedSize = totalSize - availableSize return "外部存儲總?cè)萘?${totalSize} 外部存儲可用容量:${availableSize} 外部存儲已用容量:${usedSize}" } return "" }
//內(nèi)部存儲 infoText.text = checkInternalStorageInfo() private fun checkInternalStorageInfo(): String { val path = Environment.getDataDirectory() // 內(nèi)部存儲根目錄 val stat = StatFs(path.path) val blockSize = stat.blockSizeLong // 每個block的大小 val totalBlocks = stat.blockCountLong // 總block數(shù) val availableBlocks = stat.availableBlocksLong // 可用block數(shù) val totalSize = blockSize * totalBlocks // 總?cè)萘? val availableSize = blockSize * availableBlocks // 可用容量 val usedSize = totalSize - availableSize // 已用容量 return "內(nèi)部存儲總?cè)萘?${totalSize} 內(nèi)部存儲可用容量:${availableSize} 內(nèi)部存儲已用容量:${usedSize}" }
CPU內(nèi)核數(shù)量
獲取CPU的內(nèi)核數(shù)量很簡單,Runtime
類中有現(xiàn)成的方法
infoText.text = checkCPUcoreNumber() private fun checkCPUcoreNumber() = "cpu核心數(shù) : ${Runtime.getRuntime().availableProcessors()}"
CPU架構(gòu)
infoText.text = checkCPUArchitecture() private fun checkCPUArchitecture() = "cpu架構(gòu):${Build.SUPPORTED_ABIS[0]}"
CPU硬件信息
infoText.text = checkCPUHardware() private fun checkCPUHardware() = "硬件信息:${Build.HARDWARE}"
檢測設(shè)備是否root
同樣的沒有任何api可以直接去判斷設(shè)備是否有root權(quán)限,我們只能從以下幾個方式去判斷
- 判斷檢查是否存在相關(guān)root文件
var fileRooted = false val paths = arrayOf( "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su" ) for (path in paths) { if (File(path).exists()) { fileRooted = true } }
- 檢查是否存在su命令
var suCmdExest = false var process: Process? = null try { process = Runtime.getRuntime().exec(arrayOf("which", "su")) val reader = BufferedReader(InputStreamReader(process.inputStream)) suCmdExest = reader.readLine() != null } catch (e: Exception) { suCmdExest = false } finally { process?.destroy() }
- 檢查
Build.TAGS
里面是否存在test-keys
var testKeys = false val buildTags = Build.TAGS testKeys = buildTags != null && buildTags.contains("test-keys")
- 執(zhí)行su命令
var suCmdExecute = false var suprocess: Process? = null try { suprocess = Runtime.getRuntime().exec("su") val out = suprocess.outputStream out.write("exit\n".toByteArray()) out.flush() out.close() suCmdExecute = suprocess.waitFor() == 0 } catch (e: java.lang.Exception) { suCmdExecute = false } finally { process?.destroy() }
- Magisk 文件是否存在
var giskFile = false val magiskPaths = arrayOf( "/sbin/.magisk", "/sbin/magisk", "/cache/.disable_magisk", "/cache/magisk.log", "/data/adb/magisk", "/data/adb/modules", "/data/magisk", "/data/magisk.img" ) for (path in magiskPaths) { if (File(path).exists()) { giskFile = true } }
保險起見,可以把上述幾個變量放在一起判斷設(shè)備是否有root權(quán)限
val gotRoot = fileRooted || suCmdExest || testKeys || suCmdExecute || giskFile
網(wǎng)絡(luò)情況
這個也是在應(yīng)用當中經(jīng)常會用到的一個屬性,判斷設(shè)備是連接的是wifi,還是連接的是2,3,4,5G網(wǎng)絡(luò),首先通過獲取 NetworkCapabilities
來判斷是否連接的是wifi還是移動網(wǎng)絡(luò)
private fun checkNetworkType(): String { var net = "" val cManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val capabilities: NetworkCapabilities? = cManager.getNetworkCapabilities(cManager.activeNetwork) capabilities?.let { cb -> if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { net = "WIFI" } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { net = getMobileNetworkType(cManager) } } return "網(wǎng)絡(luò)情況:${net}" }
當判斷出非wifi網(wǎng)絡(luò)的時候,再通過getMobileNetworkType
函數(shù)來得出具體的網(wǎng)絡(luò)類型
private fun getMobileNetworkType(cManager: ConnectivityManager): String { val networkInfo = cManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) if (networkInfo != null) { val networkType = networkInfo.subtype return when (networkType) { TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_EDGE -> "2G" TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_HSPA -> "3G" TelephonyManager.NETWORK_TYPE_LTE -> "4G" TelephonyManager.NETWORK_TYPE_NR -> "5G" else -> "UNKNOWN" } } return "UNKNOWN" }
總結(jié)
文章就到此為止,在拿這些信息的時候,發(fā)現(xiàn)有不少api都已經(jīng)廢棄了,所以還是要注意一下盡量別用廢棄的api去實現(xiàn)功能,防止以后出問題。
以上就是Android相關(guān)硬件信息的獲取方式整理匯總的詳細內(nèi)容,更多關(guān)于Android硬件信息獲取的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android如何在root設(shè)備上開啟ViewServer詳解
這篇文章主要給大家介紹了關(guān)于Android中如何在root設(shè)備上開啟ViewServer的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對各位Android開發(fā)者具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2017-12-12Android Studio 1.2版安裝設(shè)置圖文教程
這篇文章主要介紹了Android Studio 1.2版安裝設(shè)置圖文教程,本文詳細講解了下載、安裝Android Studio 1.2教程,以及常用設(shè)置詳細圖文教程,需要的朋友可以參考下2015-05-05Kotlin Service服務(wù)組件開發(fā)詳解
這幾天分析了一下的啟動過程,于是乎,今天寫一下Service使用; 給我的感覺是它并不復(fù)雜,千萬不要被一坨一坨的代碼嚇住了,雖然彎彎繞繞不少,重載函數(shù)一個接著一個,就向走迷宮一樣,但只要抓住主線閱讀,很快就能找到出口2022-12-12Android 中SwipeRefreshLayout與ViewPager滑動事件沖突解決方法
這篇文章主要介紹了Android 中SwipeRefreshLayout與ViewPager滑動事件沖突解決方法的相關(guān)資料,需要的朋友可以參考下2017-04-04android跑馬燈出現(xiàn)重復(fù)跳動以及不滾動問題的解決方法
這篇文章主要介紹了android跑馬燈出現(xiàn)重復(fù)跳動以及不滾動問題的解決方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09