Skip to content

Commit

Permalink
Fix crash after long-time lockscreen
Browse files Browse the repository at this point in the history
  • Loading branch information
LinZong committed Apr 27, 2021
1 parent 911ba73 commit bfff510
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 28 deletions.
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ dependencies {
exclude group: 'com.android.support.constraint', module: 'constraint-layout'
}

// backport Future support
implementation 'net.sourceforge.streamsupport:android-retrofuture:1.7.3'

implementation 'org.greenrobot:eventbus:3.2.0'
implementation 'me.weishu:free_reflection:3.0.1'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.AlertDialog
import android.content.Intent
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.support.v4.view.ViewCompat
import android.support.v7.widget.LinearLayoutManager
Expand All @@ -29,11 +30,14 @@ import com.nemesiss.dev.piaprobox.model.MusicPlayerActivityStatus
import com.nemesiss.dev.piaprobox.R
import com.nemesiss.dev.piaprobox.Service.AsyncExecutor
import com.nemesiss.dev.piaprobox.Service.DaggerFactory.DaggerDownloadServiceFactory
import com.nemesiss.dev.piaprobox.Service.DaggerFactory.DaggerImageCacheFactory
import com.nemesiss.dev.piaprobox.Service.DaggerModules.DownloadServiceModules
import com.nemesiss.dev.piaprobox.Service.DaggerModules.ImageCacheModules
import com.nemesiss.dev.piaprobox.Service.Download.DownloadService
import com.nemesiss.dev.piaprobox.Service.GlideApp
import com.nemesiss.dev.piaprobox.Service.HTMLParser
import com.nemesiss.dev.piaprobox.Service.HTMLParser.Companion.GetAlbumThumb
import com.nemesiss.dev.piaprobox.Service.ImageCache
import com.nemesiss.dev.piaprobox.Service.Player.MusicPlayerService
import com.nemesiss.dev.piaprobox.Service.Player.NewPlayer.PlayerAction
import com.nemesiss.dev.piaprobox.Service.SimpleHTTP.DaggerFetchFactory
Expand Down Expand Up @@ -226,6 +230,9 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {
@Inject
lateinit var downloadService: DownloadService

@Inject
lateinit var imageCache: ImageCache

private lateinit var htmlParser: HTMLParser
protected var relatedMusicListData: List<RelatedMusicInfo>? = null
private var relatedMusicListAdapter: RelatedMusicListAdapter? = null
Expand Down Expand Up @@ -262,17 +269,16 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {
isFirstResource: Boolean
): Boolean {
if (resource != null) {
keepLastMusicBitmap(resource)
val thumbUrl = CurrentMusicPlayInfo?.Thumb ?: return false
val fileName = Uri.parse(thumbUrl).lastPathSegment ?: return false
imageCache.cache(resource, fileName)
log.info("Image $fileName cached!")
}
return false
}
}


private fun keepLastMusicBitmap(drawable: Drawable) {
LAST_MUSIC_BITMAP = drawable.constantState?.newDrawable()?.mutate()
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
HandleSwitchMusicIntent(intent)
Expand All @@ -288,6 +294,12 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {
.build()
.inject(this)

DaggerImageCacheFactory
.builder()
.imageCacheModules(ImageCacheModules(this))
.build()
.inject(this)

ShowToolbarBackIcon(MusicPlayer_Toolbar)
// 关闭RecyclerView的嵌套滚动
ViewCompat.setNestedScrollingEnabled(MusicPlayer_Lyric_RecyclerView, false)
Expand Down Expand Up @@ -336,18 +348,8 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {
CurrentPlayItemIndex = activityStatus.currentPlayItemIndex
PLAY_LISTS = activityStatus.playLists

val lastThumbBitmap = LAST_MUSIC_BITMAP
if (lastThumbBitmap != null) {
log.info("Find valid lastThumbBitmap, reload.")
GlideApp.with(this)
.load(lastThumbBitmap)
.priority(Priority.HIGH)
.into(MusicPlayer_ThumbBackground)
keepLastMusicBitmap(lastThumbBitmap)
} else {
log.info("No valid lastThumbBitmap, load thumb from network. {}.", CurrentMusicPlayInfo?.Thumb)
GlideLoadThumbToImageView(CurrentMusicPlayInfo?.Thumb ?: "")
}
GlideLoadThumbToImageView(CurrentMusicPlayInfo?.Thumb ?: "")

ActivateLyricRecyclerViewAdapter()
ActivateRelatedMusicRecyclerViewAdapter()
}
Expand Down Expand Up @@ -425,14 +427,29 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {
}

private fun GlideLoadThumbToImageView(url: String) {

// first, touch cache for previous result.
val fileName = Uri.parse(url).lastPathSegment
if (fileName != null) {
val cacheImage = imageCache[fileName]
log.warn("Image $fileName hit cache!")
if (cacheImage != null) {
GlideApp.with(this)
.load(cacheImage)
.priority(Priority.HIGH)
.into(MusicPlayer_ThumbBackground)
log.warn("Image $fileName loaded from cache!")
return
}
}
log.warn("Image $fileName has no cache, load ahead.")
try {
GlideApp.with(this)
.load(url)
.priority(Priority.HIGH)
.addListener(MUSIC_ALBUM_LOAD_LISTENER)
.into(MusicPlayer_ThumbBackground)
} catch (e: Exception) {
}
} catch (e: Exception) { }
}

private fun playMusic(contentInfo: MusicContentInfo, playInfo: MusicPlayInfo) {
Expand Down Expand Up @@ -578,9 +595,6 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {
@JvmStatic
var LAST_MUSIC_PLAYER_ACTIVITY_STATUS: MusicPlayerActivityStatus? = null

@JvmStatic
private var LAST_MUSIC_BITMAP: Drawable? = null

@JvmStatic
var LAST_LOAD_CONTENT_URL = ""

Expand All @@ -597,11 +611,6 @@ open class MusicPlayerActivity : PiaproboxBaseActivity() {

// 音乐播放器没在播放,删掉当前播放列表
if (!MusicPlayerService.IS_FOREGROUND) {
val bitmap = (LAST_MUSIC_BITMAP as? BitmapDrawable)?.bitmap
if (bitmap?.isRecycled == false) {
bitmap.recycle()
}
LAST_MUSIC_BITMAP = null

PLAY_LISTS = null
playListCache.clear()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.nemesiss.dev.piaprobox.Service.DaggerFactory;

import com.nemesiss.dev.piaprobox.Activity.Music.MusicPlayerActivity;
import com.nemesiss.dev.piaprobox.Service.DaggerModules.ImageCacheModules;
import dagger.Component;
import dagger.Provides;

import javax.inject.Singleton;

@Singleton
@Component(modules = {ImageCacheModules.class})
public interface ImageCacheFactory {

void inject(MusicPlayerActivity activity);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.nemesiss.dev.piaprobox.Service.DaggerModules;

import android.content.Context;
import dagger.Module;
import dagger.Provides;

@Module
public class ImageCacheModules {

private Context context;

public ImageCacheModules(Context context) {
this.context = context;
}

@Provides
public Context getContext() {
return context;
}
}
112 changes: 112 additions & 0 deletions app/src/main/java/com/nemesiss/dev/piaprobox/Service/ImageCache.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.nemesiss.dev.piaprobox.Service

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Environment
import java9.util.concurrent.CompletableFuture
import okhttp3.internal.closeQuietly
import org.slf4j.getLogger
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.*
import java.util.concurrent.Future
import javax.inject.Inject

class ImageCache @Inject constructor(private val context: Context) {

private companion object {
private val log = getLogger<ImageCache>()
}

private val cacheDir = File(context.filesDir, "ImageCache")
private val async = AsyncExecutor.INSTANCE

init {
if (!cacheDir.exists()) cacheDir.mkdirs()
}


fun cache(drawable: Drawable, fileName: String): Future<Boolean> {
if (drawable is BitmapDrawable) {
val bitmap = drawable.bitmap
return cache(bitmap, fileName)
}
val bounds = drawable.bounds
val width = bounds.right - bounds.left
val height = bounds.bottom - bounds.top

if (width <= 0 || height <= 0) {
return CompletableFuture<Boolean>().apply { complete(false) }
}

val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.draw(canvas)
return cache(bitmap, fileName)
}

fun cache(bitmap: Bitmap, fileName: String): Future<Boolean> {
val format = detectCompressFormat(fileName)
return async.SendTaskWithResult task@ {
// duplicate bitmap for safe.
val cloneBitmap = Bitmap.createBitmap(bitmap)
val fos = FileOutputStream(File(cacheDir, fileName))
try {
cloneBitmap.compress(format, 100, fos)
return@task true
} catch (t: Throwable) {
log.error("Cannot save $fileName", t)
return@task false
} finally {
fos.closeQuietly()
cloneBitmap.recycle()
}
}
}

fun cache(byteArray: ByteArray, fileName: String): Future<Boolean> {
// no used, just ensure extension exists in file name.
detectCompressFormat(fileName)
return async.SendTaskWithResult task@ {
val fos = FileOutputStream(File(cacheDir, fileName))
try {
fos.write(byteArray)
return@task true
} catch (t: Throwable) {
log.error("Cannot save byte array for $fileName", t)
return@task false
} finally {
fos.closeQuietly()
}
}
}

operator fun get(fileName: String): ByteArray? {
val cacheFile = File(cacheDir, fileName)
if (!cacheFile.exists()) return null
val fis = FileInputStream(cacheFile)
val result = fis.readBytes()
fis.closeQuietly()
return result
}

private fun detectCompressFormat(fileName: String): Bitmap.CompressFormat {
val extDotIndex = fileName.lastIndexOf('.')
if (extDotIndex == -1) {
throw IllegalArgumentException("Filename $fileName must include format extension like png, jpg or webp.")
}
var extension = fileName.substring(extDotIndex + 1)
extension = extension.trim().toLowerCase(Locale.CHINA)

return when (extension) {
"png" -> Bitmap.CompressFormat.PNG
"jpg", "jpeg" -> Bitmap.CompressFormat.JPEG
"webp" -> Bitmap.CompressFormat.WEBP
else -> throw IllegalArgumentException("Filename $fileName must include format extension like png, jpg or webp.")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,4 @@ class CookieParserTest {
assertFalse(cookie.isSecure)
asEquals("/", cookie.path)
}

}
10 changes: 10 additions & 0 deletions app/src/test/java/com/nemesiss/dev/piaprobox/UriTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.nemesiss.dev.piaprobox

import android.net.Uri
import org.junit.Assert
import org.junit.Test
import java.net.URL

class UriTest {

}

0 comments on commit bfff510

Please sign in to comment.