【发布时间】:2019-09-27 13:58:35
【问题描述】:
我对这段代码有一个问题,其中return packageSize 语句在onGetStatsCompleted 函数之前触发,它返回0 而不是正确的值。
有没有办法可以强制onGetStatsCompleted 在返回packageSize 之前完成?
我知道这是一个逻辑问题,因为如果我删除 //Thread.sleep 的评论,它会正常工作。
如何在不使用Thread.sleep 或应用程序中的任何其他类型超时的情况下解决此问题?
原始代码:
/**
Get the size of the app for API < 26
*/
@Throws(InterruptedException::class)
fun getPackageSize(): Long {
val pm = context.packageManager
try {
val getPackageSizeInfo = pm.javaClass.getMethod(
"getPackageSizeInfo", String::class.java, IPackageStatsObserver::class.java)
getPackageSizeInfo.invoke(pm, context.packageName,
object : CachePackState() {//Call inner class
})
} catch (e: Exception) {
e.printStackTrace()
}
//Thread.sleep(1000)
return packageSize
}
/**
Inner class which will get the data size for the application
*/
open inner class CachePackState : IPackageStatsObserver.Stub() {
override fun onGetStatsCompleted(pStats: PackageStats, succeeded: Boolean) {
//here the pStats has all the details of the package
dataSize = pStats.dataSize
cacheSize = pStats.cacheSize
apkSize = pStats.codeSize
packageSize = cacheSize + apkSize
}
}
编辑代码:
这是 StorageInformation 类
import android.annotation.SuppressLint
import android.app.usage.StorageStatsManager
import android.content.Context
import android.content.pm.IPackageStatsObserver
import android.content.pm.PackageManager
import android.content.pm.PackageStats
/**
This class will perform data operation
*/
internal class StorageInformation(internal var context: Context) {
private var packageSize: Long = 0
private var dataSize: Long = 0
private var cacheSize: Long = 0
private var apkSize: Long = 0
/**
Get the size of the app
*/
@Throws(InterruptedException::class)
suspend fun getPackageSize(): Long {
val pm = context.packageManager
@SuppressLint("WrongConstant")
val storageStatsManager: StorageStatsManager
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
storageStatsManager = context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
try {
val ai = context.packageManager.getApplicationInfo(context.packageName, 0)
val storageStats = storageStatsManager.queryStatsForUid(ai.storageUuid, pm.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA).uid)
cacheSize = storageStats.cacheBytes
apkSize = storageStats.appBytes
packageSize = cacheSize + apkSize
} catch (e: Exception) {
e.printStackTrace()
}
} else {
try {
val getPackageSizeInfo = pm.javaClass.getMethod(
"getPackageSizeInfo", String::class.java, IPackageStatsObserver::class.java)
getPackageSizeInfo.invoke(pm, context.packageName,
object : CachePackState() {//Call inner class
})
} catch (e: Exception) {
e.printStackTrace()
}
}
return packageSize
}
/**
Inner class which will get the data size for the application
*/
open inner class CachePackState : IPackageStatsObserver.Stub() {
override fun onGetStatsCompleted(pStats: PackageStats, succeeded: Boolean) {
//here the pStats has all the details of the package
dataSize = pStats.dataSize
cacheSize = pStats.cacheSize
apkSize = pStats.codeSize
packageSize = cacheSize + apkSize
}
}
}
从接口调用 StorageInformation
var appSize=""
fun getPackageSize(callback: (Long) -> Unit) {
launch(Dispatchers.IO) {
val size = StorageInformation(getApplicationContext()).getPackageSize()
callback(size)
}
}
fun handlePackageSize(size: Long) {
launch(Dispatchers.Main) {
appSize = formatFileSize(getApplicationContext(), size)
}
}
getPackageSize(::handlePackageSize)
我也尝试了 r2rek 的解决方案并得到相同的结果
try {
GlobalScope.launch(Dispatchers.Main){
var getPackageSizeInfo = withContext(coroutineContext) {
pm.javaClass.getMethod(
"getPackageSizeInfo", String::class.java, IPackageStatsObserver::class.java)
}
getPackageSizeInfo.invoke(pm, context.packageName,
object : CachePackState() {//Call inner class
})
}
} catch (e: Exception) {
e.printStackTrace()
}
}
return packageSize
如有任何问题,请随时提出,我们将不胜感激。
【问题讨论】:
标签: android kotlin return logic