三方库引入
4. Glide加载图片异常问题
-
com.bumptech.glide.load.resource.bitmap.VideoDecoder$VideoDecoderException: MediaMetadataRetriever failed to retrieve a frame without throwing, check the adb logs for .MetadataRetriever. prior to this exception for details
- 加载非图片后缀链接
(例非.jpg、.png等格式图片)报错 - 加载涉及版权或加密图片
(例https://cdn4.vectorstock.com地址图片)报错
- 加载非图片后缀链接
-
错误代码示例
(不确定的链接最好不要用Glide直接加载)
val requestImageListener = object : RequestListener<Bitmap> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
LogTool.d("loading failed")
return true
}
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
if (resource == null) {
LogTool.i("loading bitmap is null")
} else {
LogTool.i("loading bitmap success")
}
return true
}
}
Glide.with(context)
.asBitmap()
.downsample(DownsampleStrategy.CENTER_INSIDE)
.load(url)
.timeout(15000)
.listener(requestImageListener)
.submit()
- 正确示例
(仅解决非法后缀问题)
// XxxApi.kt
@GET
suspend fun downloadImage(@Url url: String): Response<ResponseBody?>?
// @POST("xxx-api/xxx/downloadImages")
// suspend fun downloadImage(@Body url: Array<String>): ImageDownloadEntity?
// XxxRepository.kt
suspend fun downloadImage(url: String): Response<ResponseBody?>? = requestResponse { XxxClient.instance.downloadImage(url) }
suspend fun <T> requestResponse(requestCall: suspend () -> T?): T? =
withContext(Dispatchers.IO) {
withTimeout(15000) {
requestCall()
}
}
// XxxClient.kt
private const val BASE_URL = "https://xxx.xxx.com/"
val instance: XxxApi by lazy {
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build()
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(XxxApi::class.java)
}
// XxxViewModel.kt
val imageFileData = MutableLiveData<File?>()
fun downloadImage(url: String) {
launchUI(errorBlock = {
imageFileData.value = null
}, responseBlock = {
val response = repository.downloadImage(url)
if (response?.isSuccessful == true) {
val fileName = "Xxx_${System.currentTimeMillis()}.jpg"
LogTool.i("download fileName: $fileName")
imageFileData.value = outputFile(fileName, response.body())
} else {
LogTool.w("download image error")
imageFileData.value = null
}
})
}
fun launchUI(errorBlock: (e: Exception) -> Unit, responseBlock: suspend () -> Unit) {
viewModelScope.launch(Dispatchers.Main) {
safeApiCall(errorBlock = errorBlock, responseBlock)
}
}
suspend fun <T> safeApiCall(
errorBlock: suspend (e: Exception) -> Unit,
responseBlock: suspend () -> T?
): T? {
try {
return responseBlock()
} catch (e: Exception) {
LogTool.e("Exception: ${e.message}")
errorBlock(e)
}
return null
}
fun outputFile(name: String, body: ResponseBody?): File? {
body?:return null
val file = File(saveFolder(), name)
if (file.exists()) {
file.delete()
}
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
val bytes = ByteArray(4096)
val contentLength = body.contentLength()
var downloadSize: Long = 0
try {
inputStream = body.byteStream()
outputStream = FileOutputStream(file)
var lastPre = -1
while (true) {
val read = inputStream.read(bytes)
if (read == -1) {
break
}
outputStream.write(bytes, 0, read)
downloadSize += read
val percent = ((downloadSize / contentLength).toDouble() * 100).roundToInt()
if (lastPre != percent) {
lastPre = percent
}
}
outputStream.flush()
return file
} catch (e: IOException) {
LogTool.e("e: $e")
} finally {
inputStream?.close()
outputStream?.close()
}
return null
}
private fun saveFolder(): File {
var file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"Xxx" + File.separator
)
if (!file.exists() && !file.mkdirs()) {
file = Environment.getExternalStorageDirectory()
}
return file
}
3. 项目依赖多个三方库且三方库同时导入同名的.so文件,初始化时找不到so问题
- 以如下两个依赖为例
- 两个依赖同时引入了
libc++_shared.so库,apk编译时最终只会保留一个同名的so库,无法保证保留的是哪个
- 两个依赖同时引入了
implementation("org.opencv:opencv:4.11.0")
implementation("com.myscript:iink:3.0.0")
- 解决思路
- 1.若so位于某一个依赖库的lib中,可通过排除解决
- 2.检查两依赖库版本,同时升至最新版本,保证依赖so版本一致
// 方法1(不一定有效,根据实际情况处理)
implementation('com.example:library:1.0.0') {
exclude group: 'com.example', module: 'libexample'
}
// 方法2升至依赖最新版本(不一定最新,相匹配版本即可,亲测有效)
implementation("org.opencv:opencv:4.11.0")
implementation("com.myscript:iink:4.0.0")
2. 三方库引入权限查看
- 生成apk时会同步生成
manifest-merger-report.txt文件,可查看相关merge信息 - build/outputs/logs/xxx-repoprt.txt
1. java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/~/com.xxx/lib/arm64/libc++_shared.so" has bad ELF magic: 00000000
接入MyScript OCR识别so库报错
- build.gradle移除packagingOptions配置
android {
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
}
...
}
- 添加MyScript混淆(proguard-rules.pro)
-keep class com.myscript.** {*;}