安卓app,MediaPlayer播放本地音频 | 按钮控制播放和停止

简介: 在Jetpack Compose中,不直接操作原生Android组件如`Button`和`MediaPlayer`,而是使用Compose UI构建器定义界面并结合ViewModel管理音频播放逻辑。以下示例展示如何播放本地音频并用按钮控制播放/停止:创建一个`AudioPlayerViewModel`管理`MediaPlayer`实例和播放状态,然后在Compose UI中使用`Button`根据`isPlaying`状态控制播放。记得在`MainActivity`设置Compose UI,并处理相关依赖和权限。

本文讨论内容基于 Jetpack Compose 框架



在Jetpack Compose中,我们通常不会直接操作Android的原生组件(如ButtonMediaPlayer),而是会利用Compose的UI构建器来定义UI,并可能使用ViewModel和Lifecycle等组件来管理音频播放的逻辑。

以下是一个简单的例子,展示了如何在Jetpack Compose中使用MediaPlayer来播放本地音频,并使用按钮来控制播放和停止。

首先,你需要在你的项目中添加一个ViewModel来管理MediaPlayer的实例和播放状态。


viewModel

import android.content.Context  
import android.media.MediaPlayer  
import androidx.lifecycle.MutableLiveData  
import androidx.lifecycle.ViewModel  
  
class AudioPlayerViewModel : ViewModel() {  
    private var mediaPlayer: MediaPlayer? = null  
  
    // 播放状态  
    val isPlaying = MutableLiveData<Boolean>(false)  
  
    // 初始化MediaPlayer并准备播放  
    fun initPlayer(context: Context, audioResourceId: Int) {  
        mediaPlayer = MediaPlayer.create(context, audioResourceId)  
        mediaPlayer?.setOnPreparedListener {  
            isPlaying.value = false  
        }  
    }  
  
    // 播放音频  
    fun play() {  
        mediaPlayer?.start()  
        isPlaying.value = true  
    }  
  
    // 暂停音频  
    fun pause() {  
        mediaPlayer?.pause()  
        isPlaying.value = false  
    }  
  
    // 停止并释放MediaPlayer  
    fun stopAndRelease() {  
        mediaPlayer?.stop()  
        mediaPlayer?.release()  
        mediaPlayer = null  
        isPlaying.value = false  
    }  
  
    // 检查是否正在播放  
    fun isCurrentlyPlaying(): Boolean {  
        return mediaPlayer?.isPlaying ?: false  
    }  
}



Compose UI

接下来,在你的Compose UI中,你可以使用Button组件来控制播放和停止,并使用Observer来观察播放状态


import android.content.Context  
import androidx.activity.ComponentActivity  
import androidx.activity.compose.setContent  
import androidx.compose.foundation.layout.*  
import androidx.compose.runtime.*  
import androidx.compose.ui.Modifier  
import androidx.compose.ui.tooling.preview.Preview  
import androidx.lifecycle.ViewModelProvider  
import androidx.lifecycle.viewmodel.compose.viewModel  
import com.google.accompanist.insets.navigationBarsPadding  
import com.google.accompanist.insets.statusBarsPadding  
  
@Composable  
fun AudioPlayerScreen(context: Context) {  
    val viewModel: AudioPlayerViewModel = viewModel()  
  
    viewModel.initPlayer(context, R.raw.your_audio_file) // 替换为你的音频文件资源ID  
  
    BoxWithConstraints(  
        modifier = Modifier  
            .fillMaxSize()  
            .statusBarsPadding()  
            .navigationBarsPadding()  
    ) {  
        Column(  
            modifier = Modifier  
                .fillMaxSize()  
                .padding(16.dp),  
            verticalArrangement = Arrangement.Center,  
            horizontalAlignment = Alignment.CenterHorizontally  
        ) {  
            Button(  
                onClick = {  
                    if (viewModel.isCurrentlyPlaying()) {  
                        viewModel.pause()  
                    } else {  
                        viewModel.play()  
                    }  
                }  
            ) {  
                Text(  
                    if (viewModel.isPlaying.value == true) "Pause" else "Play",  
                    style = MaterialTheme.typography.button  
                )  
            }  
  
            // 这里可以添加更多UI元素,如播放进度条等  
        }  
    }  
  
    // 清理MediaPlayer资源  
    DisposableEffect(Unit) {  
        onDispose {  
            viewModel.stopAndRelease()  
        }  
    }  
}  
  
@Preview(showBackground = true)  
@Composable  
fun DefaultPreview() {  
    AudioPlayerScreen(LocalContext.current)  
}  
  
// 在你的Activity中设置Compose UI  
class MainActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContent {  
            AudioPlayerScreen(this)  
        }  
    }  
}


请注意,上述代码中的R.raw.your_audio_file需要替换为你的音频文件在资源目录中的ID。同时,你还需要在build.gradle文件中添加对Jetpack Compose和Accompanist(用于处理窗口内边距)的依赖。

确保你的应用有适当的权限来访问和播放音频文件。如果你的音频文件在外部存储上,你可能还需要处理运行时权限请求。







在Jetpack Compose中集成MediaPlayer以播放本地音频,并使用按钮来控制播放和停止的过程,涉及到几个关键点:状态管理、生命周期感知以及与Compose UI的交互。下面是一个示例代码片段,展示了如何在Jetpack Compose中实现这些功能。

首先,你需要在你的build.gradle文件中添加androidx.media:media依赖项,以便使用MediaPlayer



dependencies {
    implementation 'androidx.media:media:1.4.3'
}



接下来,使用下面的Composable函数来创建UI和逻辑:



import android.media.MediaPlayer
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import kotlinx.coroutines.delay

@Composable
fun MediaPlayerDemo() {
    var mediaPlayer by remember { mutableStateOf<MediaPlayer?>(null) }
    var isPlaying by remember { mutableStateOf(false) }

    LaunchedEffect(key1 = true) {
        mediaPlayer = MediaPlayer.create(LocalContext.current, R.raw.your_audio_file)
        mediaPlayer?.setOnCompletionListener {
            isPlaying = false
        }
    }

    Column(modifier = Modifier.fillMaxSize()) {
        Button(
            onClick = {
                if (!isPlaying && mediaPlayer != null) {
                    mediaPlayer?.start()
                    isPlaying = true
                }
            },
            enabled = !isPlaying
        ) {
            Text(text = "Play")
        }
        Button(
            onClick = {
                if (isPlaying && mediaPlayer != null) {
                    mediaPlayer?.pause()
                    isPlaying = false
                }
            },
            enabled = isPlaying
        ) {
            Text(text = "Stop")
        }
    }
}


在这段代码中,我们使用remember来保持MediaPlayerisPlaying状态。LaunchedEffect用于初始化MediaPlayer,并设置一个完成监听器,以便在音频播放完毕时停止播放状态。

两个Button分别用于控制播放和停止。onClick回调根据当前的播放状态来决定是否应该开始播放或暂停播放。

请确保替换R.raw.your_audio_file为你自己的音频资源ID。此外,由于LocalContext.current在Compose中可能不总是返回正确的上下文,你可能需要根据你的具体需求调整获取上下文的方式,例如从ViewModel或Application中获取。

这段代码提供了一个基本的框架,你可以在此基础上添加错误处理、更复杂的UI元素,或者根据应用的需求进行扩展。



目录
打赏
0
3
3
0
98
分享
相关文章
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
88 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
74 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
72 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
202 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
65 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
6月前
|
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
387 0
安卓项目:app注册/登录界面设计
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
61 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
4月前
|
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
162 11
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
209 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
7月前
|
Kotlin 在公司上网监控中的安卓开发应用
在数字化办公环境中,公司对员工上网行为的监控日益重要。Kotlin 作为一种基于 JVM 的编程语言,具备简洁、安全、高效的特性,已成为安卓开发的首选语言之一。通过网络请求拦截,Kotlin 可实现网址监控、访问时间记录等功能,满足公司上网监控需求。其简洁性有助于快速构建强大的监控应用,并便于后续维护与扩展。因此,Kotlin 在安卓上网监控应用开发中展现出广阔前景。
50 1

物联网

+关注
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等