Author: Cang Wang Time: July 12, 2018.The following is my series of related articles, you can refer to, you can give a like or follow my article.

[Android] How to make a chapter list of apps with a crash rate of less than three per thousand

The pit here is the use of the Material transition +Glide display picture.

1. The image of Material transition +Glide shows that Bitmap can transition normally.

2. If Glide loads the image and adds rounded corners to Transform, it is ok for Glide to transition to the new display page, and the back key returns to first display the original image (without rounded corners) and then display rounded corners, which feels refreshed. This can be handled directly with a rounded ImageView, and shape doesn’t work.

3. If glide loads a GIF image, it is used here to indicate that glide loads a GIF image. Using the Material transition effect, you will find that the GIF will be stuck without displaying the GIF, and only the current frame will be displayed, but after debugging, the GIF will be displayed. In case of delayed display, the GIF can be displayed normally, but there will be a period of black screen in the middle, which needs to be processed by loading. If the GIF image is rounded, do not use custom extended ImageView as rounded View, this GIF image will not play, it is better to use the native Glide Transform ImageView.

4. If YOU use Glide to load MP4, you can display the first frame normally, but if you use The Material transition, you will find that the video cannot play normally in the first second when you use Google ExoPlayer. When you pull it back, you will find that the video can play normally. This is gonna have to delay itself or go back to the normal transition.

5. The problem of obtaining the first frame of the video is used. If it is a network video, it is better to upload the picture of the first frame to the server when uploading information, otherwise, it is necessary to obtain the resources of the first frame of the video online. If the video is encrypted, it can only be completed by caching it locally. Therefore, this is too time-consuming. Please make sure to upload the video preview image when designing the protocol.

Android native provides a MediaMetadataRetriever class that provides a method to get the first frame of a URL video, returning a Bitmap object ** @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) / / here in Sring md5 as a unique identifierif(File(tmpPath).exists()) {// Determine whether the image existsreturnresult(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? = nullif(null ! Bitmap) = {path = saveBitmap2File (bitmap, EncryptUtils encryptMD5ToString (uri)) / / save to a local}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)})} /** * get the first frame of the local video ** @param uri Local URI address * @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()) {
            returnresult(uri, tmpPath) } val videoPath = FileUtils.getFileAbsolutePath(context, uri) var bitmap: Bitmap? = null val Retriever = MediaMetadataRetriever() try {// Obtain the snapshot retriever.setdatasource (videoPath) from the file path // obtain the bitmap of the first frame = retriever.frameAtTime } catch (e: IllegalArgumentException) { e.printStackTrace() } finally { retriever.release() } var imgPath: String? = nullif(null ! = bitmap) { imgPath = saveBitmap2File(bitmap, EncryptUtils.encryptMD5ToString(uri.toString())) }returnResult (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() } val path = dir + imgName val file = File(path) var out: FileOutputStream? = null try { out = FileOutputStream(file) bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)returnpath } catch (e: Exception) { e.printStackTrace() } finally { try { out? .close() } catch (e: IOException) { e.printStackTrace() } }return null
    }
Copy the code

6. If the uploaded image is in binary stream format, read the first few bytes of the file to determine the image format.

Throws(IOException::class) fun getType(filePath: String): FileType? { var fileHead: String? = getFileHeader(filePath)if (fileHead == null || fileHead.isEmpty()) {
            return null
        }
        fileHead = fileHead.toUpperCase()
        val fileTypes = FileType.values()
        for (type in fileTypes) {
            if (fileHead.startsWith(type.value)) {
                return type}}return null
    }

enum class FileType constructor(value: String) {
        JPEG("FFD8FF"),
        PNG("89504E47"),
        GIF("47494638"),
        TIFF("49492A00"),
        RTF("7B5C727466"),
        DOC("D0CF11E0"),
        XLS("D0CF11E0"),
        MDB("5374616E64617264204A"),
        BMP("424D"),
        DWG("41433130"),
        PSD("38425053"),
        XML("3C3F786D6C"),
        HTML("68746D6C3E"),
        PDF("255044462D312E"),
        ZIP("504B0304"),
        RAR("52617221"),
        WAV("57415645"),
        AVI("41564920");

        var value = ""
        init {
            this.value = value
        }
 }
Copy the code

Glide Override specifies the image size and the imageView specifies the size, and the imageView is the last to take effect, which stretches the image. If the image is in RecylverView and the image is adapted to wrAP_content, the RecylerView adjustment may be moved.

If there is any other information, it will be added here. If you encounter other problems, you can also leave a message. Thank you.

Star Technology Group QQ: 557247785.