feat:优化视频播放功能,包括下载、播放、暂停和停止视频。

This commit is contained in:
LUX-Timber 2024-04-25 11:14:05 +08:00
parent db59e63779
commit be40211f41
5 changed files with 183 additions and 64 deletions

View File

@ -4,6 +4,17 @@
<value> <value>
<entry key="app"> <entry key="app">
<State> <State>
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="D:\Android\.android\avd\Pixel_7_API_34.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<targetSelectedWithDropDown> <targetSelectedWithDropDown>
<Target> <Target>
<type value="QUICK_BOOT_TARGET" /> <type value="QUICK_BOOT_TARGET" />
@ -15,7 +26,7 @@
</deviceKey> </deviceKey>
</Target> </Target>
</targetSelectedWithDropDown> </targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-04-24T08:47:36.516818Z" /> <timeTargetWasSelectedWithDropDown value="2024-04-25T02:40:10.447031700Z" />
</State> </State>
</entry> </entry>
</value> </value>

View File

@ -1,9 +1,15 @@
package com.timber.soft.mylivewallpaper.tools package com.timber.soft.mylivewallpaper.tools
import android.content.Context
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.View import android.view.View
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.google.gson.Gson import com.google.gson.Gson
import com.jakewharton.rxbinding4.view.clicks import com.jakewharton.rxbinding4.view.clicks
import com.timber.soft.mylivewallpaper.data.WallpaperData import com.timber.soft.mylivewallpaper.data.WallpaperData
@ -14,13 +20,11 @@ import java.util.concurrent.TimeUnit
object AppTools { object AppTools {
private const val DIR_FILE_NAME = "tep"
private const val DIR_DOWNLOAD = "download"
fun View.throttleClicks(time: Long = 1000, block: (View) -> Unit) { fun View.throttleClicks(time: Long = 1000, block: (View) -> Unit) {
this.clicks().throttleFirst(time, TimeUnit.MILLISECONDS).subscribe { block(this) } this.clicks().throttleFirst(time, TimeUnit.MILLISECONDS).subscribe { block(this) }
} }
fun onMain(operation: () -> Unit) = Handler(Looper.getMainLooper()).post(operation) fun onMain(operation: () -> Unit) = Handler(Looper.getMainLooper()).post(operation)
fun parseJsonFile(jsonInputStream: InputStream): List<WallpaperData> { fun parseJsonFile(jsonInputStream: InputStream): List<WallpaperData> {
val reader = InputStreamReader(jsonInputStream) val reader = InputStreamReader(jsonInputStream)
@ -28,39 +32,28 @@ object AppTools {
return Gson().fromJson(jsonString, Array<WallpaperData>::class.java).toMutableList() return Gson().fromJson(jsonString, Array<WallpaperData>::class.java).toMutableList()
} }
private fun getDownloadDirectory(): String { fun glideDownload(context: Context, url: String, downloadCall: (File?) -> Unit) {
return getDefaultDirectory() + File.separator + DIR_DOWNLOAD Glide.with(context).downloadOnly().load(url).addListener(object : RequestListener<File> {
} override fun onLoadFailed(
e: GlideException?,
private fun getDefaultDirectory(): String { model: Any?,
var dirName = "" target: Target<File>?,
if (MyApplication.appContext.getExternalFilesDir(DIR_FILE_NAME) != null) {//外部存储可用 isFirstResource: Boolean
if (Build.VERSION.SDK_INT >= 29) { ): Boolean {
dirName = MyApplication.appContext.getExternalFilesDir(DIR_FILE_NAME)!!.path downloadCall.invoke(null)
} else if (Build.VERSION.SDK_INT < 29) { return false
dirName = MyApplication.appContext.getExternalFilesDir(DIR_FILE_NAME)!!.absolutePath
} }
} else {
dirName = MyApplication.appContext.filesDir.absolutePath override fun onResourceReady(
} resource: File?,
return dirName model: Any?,
target: Target<File>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
downloadCall.invoke(resource)
return false
}
}).preload()
} }
fun getFileName(url: String): String {
return url.substring(url.lastIndexOf("/") + 1)
}
fun getFilePath(url: String): String {
return getDownloadDirectory() + File.separator + getFileName(url)
}
fun getFile(url: String): File {
return File(getFilePath(url))
}
fun isExist(url: String): Boolean {
return File(getFilePath(url)).exists()
}
} }

View File

@ -2,10 +2,13 @@ package com.timber.soft.mylivewallpaper.ui.activity
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.media.MediaPlayer
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.view.SurfaceHolder
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.core.view.isVisible
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
@ -13,11 +16,12 @@ import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import com.timber.soft.mylivewallpaper.R
import com.timber.soft.mylivewallpaper.data.AppDatabase import com.timber.soft.mylivewallpaper.data.AppDatabase
import com.timber.soft.mylivewallpaper.data.WallpaperData import com.timber.soft.mylivewallpaper.data.WallpaperData
import com.timber.soft.mylivewallpaper.databinding.ActivityDetailsBinding import com.timber.soft.mylivewallpaper.databinding.ActivityDetailsBinding
import com.timber.soft.mylivewallpaper.tools.AppFinalString import com.timber.soft.mylivewallpaper.tools.AppFinalString
import com.timber.soft.mylivewallpaper.tools.AppTools.isExist import com.timber.soft.mylivewallpaper.tools.AppTools.glideDownload
import com.timber.soft.mylivewallpaper.ui.customerView.DownLoadDialog import com.timber.soft.mylivewallpaper.ui.customerView.DownLoadDialog
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -28,6 +32,9 @@ class DetailActivity : BaseActivity(), View.OnClickListener {
private lateinit var binding: ActivityDetailsBinding private lateinit var binding: ActivityDetailsBinding
private lateinit var wallpaperData: WallpaperData private lateinit var wallpaperData: WallpaperData
private lateinit var downDialog: DownLoadDialog private lateinit var downDialog: DownLoadDialog
private var mediaPlayer: MediaPlayer? = null
private lateinit var videoUrl: String
private var isDownload = false
override fun getActivityContentView(): View { override fun getActivityContentView(): View {
binding = ActivityDetailsBinding.inflate(layoutInflater) binding = ActivityDetailsBinding.inflate(layoutInflater)
return binding.root return binding.root
@ -85,6 +92,7 @@ class DetailActivity : BaseActivity(), View.OnClickListener {
binding.detailsCollect.setOnClickListener(this) binding.detailsCollect.setOnClickListener(this)
binding.detailsSet.setOnClickListener(this) binding.detailsSet.setOnClickListener(this)
binding.detailsPlayButton.setOnClickListener(this) binding.detailsPlayButton.setOnClickListener(this)
binding.detailsVideoBack.setOnClickListener(this)
binding.detailsCollect.isSelected = wallpaperData.isCollect binding.detailsCollect.isSelected = wallpaperData.isCollect
} }
@ -103,15 +111,32 @@ class DetailActivity : BaseActivity(), View.OnClickListener {
} }
binding.detailsPlayButton -> { binding.detailsPlayButton -> {
if (isExist()) { if (isDownload) {
binding.detailsPlayButton.isVisible = false
playVideo() playVideo()
} else { } else {
binding.detailsPlayButton.isVisible = false
binding.detailsProgressbar.isVisible = true
showDownloadDialog() showDownloadDialog()
} }
} }
binding.detailsVideoBack -> {
stopVideo()
}
} }
} }
private fun stopVideo() {
try {
mediaPlayer?.stop()
} catch (e: Exception) {
e.printStackTrace()
}
binding.detailsFlPlay.isVisible = false
binding.detailsPlayButton.isVisible = true
}
private fun setCollect() { private fun setCollect() {
if (!binding.detailsCollect.isSelected) { if (!binding.detailsCollect.isSelected) {
binding.detailsCollect.isSelected = !binding.detailsCollect.isSelected binding.detailsCollect.isSelected = !binding.detailsCollect.isSelected
@ -138,15 +163,119 @@ class DetailActivity : BaseActivity(), View.OnClickListener {
} }
private fun showDownloadDialog() { private fun showDownloadDialog() {
Log.e("file_play", "file is null!") wallpaperData.preview.let {
glideDownload(this, it) { file ->
if (file == null) {
isDownload = false
Toast.makeText(
this@DetailActivity, "Sorry, the download failed.", Toast.LENGTH_SHORT
).show()
binding.detailsProgressbar.isVisible = false
} else {
binding.detailsProgressbar.isVisible = false
file.absolutePath.let { path ->
// mediaPlayer.setDataSource(path)
// mediaPlayer.prepare()
videoUrl = path
isDownload = true
CoroutineScope(Dispatchers.IO).launch {
AppDatabase.dataBase.getWallpaperDao().insertData(wallpaperData.apply {
downloadUrl = path
})
}
playVideo()
}
}
}
}
} }
private fun playVideo() { private fun playVideo() {
Log.e("file_play", "file is exist!") try {
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer()
binding.detailsSurfaceVideo.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
try {
mediaPlayer?.reset()
mediaPlayer?.setDataSource(videoUrl)
mediaPlayer?.setDisplay(holder)
mediaPlayer?.isLooping = true
mediaPlayer?.setVolume(0f, 0f)
mediaPlayer?.setOnPreparedListener {
try {
it.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
mediaPlayer?.prepareAsync()
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
}
})
} else {
mediaPlayer?.reset()
mediaPlayer?.setDataSource(videoUrl)
mediaPlayer?.isLooping = true
mediaPlayer?.setVolume(0f, 0f)
mediaPlayer?.prepare()
}
binding.detailsFlPlay.isVisible = true
} catch (e: Exception) {
e.printStackTrace()
}
} }
private fun isExist(): Boolean { override fun onDestroy() {
return isExist(wallpaperData.preview) super.onDestroy()
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
}
override fun onBackPressed() {
super.onBackPressed()
if (binding.detailsFlPlay.isVisible) {
stopVideo()
return
}
finish()
}
override fun onPause() {
super.onPause()
if (binding.detailsFlPlay.isVisible) {
try {
stopVideo()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onResume() {
super.onResume()
if (binding.detailsFlPlay.isVisible) {
try {
mediaPlayer?.start()
} catch (e: Exception) {
e.printStackTrace()
}
}
} }
} }

View File

@ -10,23 +10,11 @@ import com.timber.soft.mylivewallpaper.databinding.ViewDownloaddialogBinding
import com.timber.soft.mylivewallpaper.tools.AppTools.throttleClicks import com.timber.soft.mylivewallpaper.tools.AppTools.throttleClicks
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
/**
* TODO : no implement
*/
class DownLoadDialog( class DownLoadDialog(
private val context: Context, private val context: Context,
private val url: String, private val url: String,
private val title: String = "",
init: DownLoadDialog.() -> Unit
) : Dialog(context, R.style.DownLoadDialog) { ) : Dialog(context, R.style.DownLoadDialog) {
private lateinit var binding: ViewDownloaddialogBinding private lateinit var binding: ViewDownloaddialogBinding
var onDownloadSuccess: (() -> Unit)? = null
var onDownloadFailed: (() -> Unit)? = null
private var mCount: AtomicInteger = AtomicInteger(0)
init {
init()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -43,13 +31,10 @@ class DownLoadDialog(
} }
private fun startDownload() { private fun startDownload() {
binding.dialogProgressbar.progress = 0f
} }
private fun initView() { private fun initView() {
if (!TextUtils.isEmpty(title)) {
binding.dialogText.text = title
}
binding.dialogIvClose.throttleClicks { binding.dialogIvClose.throttleClicks {
dismiss() dismiss()
} }

View File

@ -94,14 +94,15 @@
android:visibility="visible" /> android:visibility="visible" />
<ImageView <ImageView
android:id="@+id/details_ivClose" android:id="@+id/details_video_back"
android:layout_width="54dp" android:layout_width="54dp"
android:layout_height="54dp" android:layout_height="54dp"
android:layout_gravity="end" android:layout_gravity="start"
android:layout_marginStart="24dp"
android:layout_marginTop="46dp" android:layout_marginTop="46dp"
android:layout_marginEnd="24dp" android:background="@drawable/shape_circular"
android:src="@drawable/svg_back" android:padding="12dp"
android:visibility="visible" /> android:src="@drawable/svg_back" />
</FrameLayout> </FrameLayout>