IM 使用的图片显示问题研究

269 阅读3分钟
原文链接: xiaozhuanlan.com

1.使用了Material过渡+Glide的图片显示Bitmap能正常过渡的。

2.如果Glide加载图片加入圆角的Transform,此时glide过渡到新的显示页没问题,back键返回首先显示原图(不带圆角)然后再显示圆角,这是感觉会被刷新了一下。这里可以直接用圆角的ImageView来处理,用shape是无效的。

3.如果glide加载的是gif图片,这里使用是要使用asGif提示Glide加载的是gif图。使用material过渡效果,会发现,gif图会被卡住不显示动图,只显示当前帧,使用调试后却了显示动图的情况。如果延迟显示也是能正常显示动图,但是中间会有一段时间黑屏需要用loading处理。如果gif图加上圆角,不要使用自定义扩展ImageView作为圆角View,这样gif图会播放不了,最好使用原生的Glide Transform+ImageView。

4.如果使用glide加载mp4,能正常显示首帧,但是如果使用了material过渡,使用google的exoplayer会发现开始的一秒视频无法正常播放,拉回去发现是可以播放出来的,这里估计是绘制繁忙导致的,这里还是得自行延迟处理或者换回正常的过渡方式了。

5.使用获取视频首帧的问题,这里如果是网络视频最好是上传信息时,已经将首帧的图上传服务器,不然需要在线获取视频的首帧资源。如果视频经过加密处理,那么只能先缓存到本地才能完成,所以这种折腾太过耗时,请设计协议时一定要设计上传视频预览图。
```
/**
* 通过url去获取视频的第一帧
* Android 原生给我们提供了一个MediaMetadataRetriever类
* 提供了获取url视频第一帧的方法,返回Bitmap对象
*
* @param videoUrl
* @return
*/
fun getPreviewFromUri(uri: String?, result: (url: String?, previewPath: String?) -> Unit) {
if (uri == null) {
return result(null, null)
}
val tmpPath = Environment.getExternalStorageDirectory().toString() + File.separator + "XXX/cache/" + EncryptUtils.encryptMD5ToString(uri) //这里用Sring转md5作为唯一标识
if (File(tmpPath).exists()) { //判断图片是否存在
return result(uri, tmpPath)
}

    Observable.create(ObservableOnSubscribe<String> {

        var bitmap: Bitmap? = null

        val retriever = MediaMetadataRetriever()  //原生取帧图

        try {

            val resourceUri = uri.trim()

            if (resourceUri.startsWith("http", true)) {

                retriever.setDataSource(uri, HashMap())

            } else {

                retriever.setDataSource(uri)

            }

            bitmap = retriever.frameAtTime    //获取第一帧关键帧

        } catch (e: IllegalArgumentException) {

            e.printStackTrace()

        } finally {

            retriever.release()

        }





        var path: String? = null

        if (null != bitmap) {

            path = saveBitmap2File(bitmap, EncryptUtils.encryptMD5ToString(uri))  //保存到本地

        }



        if (null != path) {

            it.onNext(path)

        } else {

            it.onError(Exception("loading bitmap failed"))

        }

        it.onComplete()

    }).subscribeOn(Schedulers.io())

            .observeOn(AndroidSchedulers.mainThread())

            .subscribe({

                result(uri, it)

            }, {

                result(uri, null)

            })

}



/**

 * 获取本地视频的第一帧

 *

 * @param uri 本地uri地址

 * @return 预览图地址

 */

fun getLocalVideoBitmap(context: Context, uri: Uri?, result: (uri: Uri?, previewPath: String?) -> Unit) {

    if (uri == null) {

        return result(null, null)

    }

    val tmpPath = Environment.getExternalStorageDirectory().toString() + File.separator + "XXX/cache/" + EncryptUtils.encryptMD5ToString(uri.toString())

    if (File(tmpPath).exists()) {

        return result(uri, tmpPath)

    }



    val videoPath = FileUtils.getFileAbsolutePath(context, uri)

    var bitmap: Bitmap? = null

    val retriever = MediaMetadataRetriever()

    try {

        //根据文件路径获取缩略图

        retriever.setDataSource(videoPath)

        //获得第一帧图片

        bitmap = retriever.frameAtTime

    } catch (e: IllegalArgumentException) {

        e.printStackTrace()

    } finally {

        retriever.release()

    }

    var imgPath: String? = null

    if (null != bitmap) {

        imgPath = saveBitmap2File(bitmap, EncryptUtils.encryptMD5ToString(uri.toString()))

    }



    return result(uri, imgPath)

}

//保存图片到本地
fun saveBitmap2File(bitmap: Bitmap, imgName: String): String? {
val dir = Environment.getExternalStorageDirectory().toString() + File.separator + "XXX/cache/"
if (!File(dir).exists()) {
File(dir).mkdirs()