Kotlin开发:Activity启动音乐播放Service无声音问题求助
问题描述
通过Activity启动实现音乐播放能力的Service,已在AndroidManifest清单文件完成Service注册,但点击Activity界面上的启动按钮后无任何声音输出,相关Kotlin代码如下:
class MyService : Service() { lateinit var mediaPlayer:MediaPlayer override fun onCreate() { super.onCreate() Log.i("Service","service Created") mediaPlayer=MediaPlayer.create(this,R.raw.music2) } override fun onDestroy() { super.onDestroy() Log.i("Service","service Destroyed") if(mediaPlayer.isPlaying){ mediaPlayer.stop() mediaPlayer.release() } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i("Service","service Started") if(!mediaPlayer.isPlaying) mediaPlayer.start() return START_STICKY } override fun onBind(intent: Intent): IBinder { TODO("Return the communication channel to the service.") } } class MainActivity : AppCompatActivity() { lateinit var startBtn:Button lateinit var stopBtn:Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? { return super.onCreateView(name, context, attrs) Log.i("Service","activityCreated") startBtn=findViewById(R.id.startBtn) stopBtn=findViewById(R.id.stopBtn) startBtn.setOnClickListener { val intent=Intent(context,MyService::class.java) if(context!=null) context.startService(intent) } stopBtn.setOnClickListener { val intent=Intent(context,MyService::class.java) stopService(intent) } } }
核心问题点
- 按钮初始化、点击事件绑定代码属于永远不会执行的死代码:你把这部分逻辑写在了
onCreateView方法内,且方法第一行就执行了return返回,后续代码没有任何执行机会。同时AppCompatActivity通过setContentView加载布局时,不会触发你重写的这个onCreateView回调来处理布局内控件,等于两个按钮从来没绑定过点击逻辑,点击自然不会触发Service启动。 - Service的
onBind方法存在崩溃隐患:Kotlin中TODO()函数会直接抛出NotImplementedError,即使你通过startService启动Service不走绑定逻辑,异常触发时也会导致Service直接崩溃,非绑定场景下该方法直接返回null即可。 - MediaPlayer资源释放逻辑不严谨:当前仅当音频处于播放状态时才会执行stop和release操作,如果Service销毁时音频已经自然播放结束,MediaPlayer占用的资源不会被释放,后续重复启动Service容易出现状态异常。
修复方案
- 把控件初始化、点击事件绑定逻辑移到Activity的
onCreate方法中,放在setContentView调用之后执行,删除无效的onCreateView重写逻辑。 - 修改Service的
onBind方法,非绑定场景直接返回null。 - 补全MediaPlayer的释放逻辑,无论是否处于播放状态,Service销毁时都要释放资源。
修复后的完整代码:
class MyService : Service() { private lateinit var mediaPlayer: MediaPlayer override fun onCreate() { super.onCreate() Log.i("Service", "service Created") mediaPlayer = MediaPlayer.create(this, R.raw.music2) // 如需循环播放可打开下方配置 // mediaPlayer.isLooping = true } override fun onDestroy() { super.onDestroy() Log.i("Service", "service Destroyed") // 统一释放资源,无需额外判断播放状态 mediaPlayer.stop() mediaPlayer.release() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i("Service", "service Started") if (!mediaPlayer.isPlaying) { mediaPlayer.start() } return START_STICKY } override fun onBind(intent: Intent): IBinder? { // 非绑定启动模式直接返回null即可 return null } } class MainActivity : AppCompatActivity() { private lateinit var startBtn: Button private lateinit var stopBtn: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) Log.i("Service", "activityCreated") // 初始化控件、绑定点击事件 startBtn = findViewById(R.id.startBtn) stopBtn = findViewById(R.id.stopBtn) startBtn.setOnClickListener { val intent = Intent(this, MyService::class.java) startService(intent) } stopBtn.setOnClickListener { val intent = Intent(this, MyService::class.java) stopService(intent) } } }
补充说明:如果应用运行在Android 8.0(API 26)及以上版本,后台启动Service存在系统限制,建议使用
startForegroundService启动前台Service,并在Service的onCreate中调用startForeground挂载常驻通知,否则Service可能无法正常启动。
内容的提问来源于stack exchange,提问作者Beginner developer
相关产品推荐
相关产品推荐

