References underlined with "~~~" are likely causes.
Learn more at https://squ.re/leaks.
415914 bytes retained by leaking objects
Signature: 453e752cfbb380a711eb3eefef25dc6c7499fd2
┬───
│ GC Root: Input or output parameters in native code
│
├─ android.os.FileObserver$ObserverThread instance
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'FileObserver'
│ ↓ FileObserver$ObserverThread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│ Leaking: NO (XUpdate↓ is not leaking and A ClassLoader is never leaking)
│ ↓ PathClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│ Leaking: NO (XUpdate↓ is not leaking)
│ ↓ Object[].[1050]
├─ com.xuexiang.xupdate.XUpdate class
│ Leaking: NO (a class is never leaking)
│ ↓ static XUpdate.sInstance
│ ~~~~~~~~~
├─ com.xuexiang.xupdate.XUpdate instance
│ Leaking: UNKNOWN
│ ↓ XUpdate.mIUpdateDownloader
│ ~~~~~~~~~~~~~~~~~~
├─ com.xuexiang.xupdate.proxy.impl.DefaultUpdateDownloader instance
│ Leaking: UNKNOWN
│ ↓ DefaultUpdateDownloader.mServiceConnection
│ ~~~~~~~~~~~~~~~~~~
├─ com.xuexiang.xupdate.proxy.impl.DefaultUpdateDownloader$1 instance
│ Leaking: UNKNOWN
│ Anonymous class implementing android.content.ServiceConnection
│ ↓ DefaultUpdateDownloader$1.val$downloadListener
│ ~~~~~~~~~~~~~~~~~~~~
├─ com.xuexiang.xupdate.widget.UpdateDialogFragment$2 instance
│ Leaking: UNKNOWN
│ Anonymous class implementing com.xuexiang.xupdate.service.OnFileDownloadListener
│ ↓ UpdateDialogFragment$2.this$0
│ ~~~~~~
╰→ com.xuexiang.xupdate.widget.UpdateDialogFragment instance
Leaking: YES (ObjectWatcher was watching this because com.xuexiang.xupdate.widget.UpdateDialogFragment received Fragment#onDestroy() callback and Fragment#mFragmentManager is null)
设备信息
任意设备
附加信息
我重定义了IUpdateHttpService,不知道是否与此有关。
class RetrofitHttpService() : IUpdateHttpService {
private var call: Call<ResponseBody>?= null
override fun asyncGet(url: String, params: MutableMap<String, Any>, callBack: IUpdateHttpService.Callback) {
APIManager.apiService.checkUpdate(getVersion()).enqueue(object : Callback<BaseResponseBean> {
override fun onFailure(call: Call<BaseResponseBean>, t: Throwable) {
callBack.onError(t)
}
override fun onResponse(call: Call<BaseResponseBean>, response: Response<BaseResponseBean>) {
val body = response.body()
if (body == null || !body.isSuccess()) {
callBack.onError(Throwable(body?.msg ?: "网络错误"))
} else {
callBack.onSuccess(body.data.toString())
}
}
})
}
override fun asyncPost(url: String, params: MutableMap<String, Any>, callBack: IUpdateHttpService.Callback) {
}
override fun download(url: String, path: String, fileName: String, callback: IUpdateHttpService.DownloadCallback) {
call = APIManager.apiService.download(url)
call?.enqueue(
object : Callback<ResponseBody> {
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
callback.onError(t)
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
callback.onStart()
GlobalScope.launch {
writeResponseToDisk(path + fileName, response, callback)
}
}
})
}
override fun cancelDownload(url: String) {
call?.cancel()
call = null
cancelHandler()
}
private val sBufferSize = 8192
private fun writeResponseToDisk(path: String, responseBody: Response<ResponseBody>, callback: IUpdateHttpService.DownloadCallback) {
val file = File(path)
val inputStream = responseBody.body()!!.byteStream()
val totalLength = responseBody.body()!!.contentLength()
if (!file.exists()) {
if (!file.parentFile.exists()) {
file.parentFile.mkdir()
}
try {
file.createNewFile()
} catch (e: IOException) {
runOnMainThread {
callback.onError(e)
}
}
}
var currentLength = 0
try {
val os = BufferedOutputStream(FileOutputStream(file))
var data = ByteArray(8192)
var len = 0
while ((inputStream.read(data, 0, sBufferSize).also { len = it }) != -1) {
os.write(data, 0, len)
currentLength += len
runOnMainThread {
callback.onProgress(currentLength / totalLength.toFloat(), totalLength)
}
}
runOnMainThread {
callback.onSuccess(file)
}
os.close()
} catch (e: IOException) {
callback.onError(e)
} finally {
try {
inputStream.close()
} catch (e: Exception) {
runOnMainThread {
callback.onError(e)
}
}
}
}
}
问题描述(必填) 当在下载中取消下载,内存泄漏
使用的XUpdate版本(必填) 2.0.2
如何重现(必填) 重现的步骤: 在应用程序启动后检查更新
期望的效果 内存不泄漏
截图 日志:
设备信息 任意设备
附加信息 我重定义了IUpdateHttpService,不知道是否与此有关。