Android一次完美的跨进程服务共享实践,android界面开发基础

包含公司所有需要集成录音服务的端,这里不需要解释

Manager层

该层负责Service层的管理,包括:服务的绑定,解绑,注册回调,开启录音,停止录音,检查录音状态,检查服务运行状态等 ###Service层 核心逻辑层,通过AIDL的实现,来满足跨进程通信,并提供实际的录音功能。

目录一览

看代码目录的分配,并结合架构图,我们来从底层往上层实现一套逻辑

IRecorder 接口定义

public interface IRecorder {

String startRecording(RecorderConfig recorderConfig);

void stopRecording();

RecorderState state();

boolean isRecording();

}

IRecorder 接口实现

class JLMediaRecorder : IRecorder {

private var mMediaRecorder: MediaRecorder? = null

private var mState = RecorderState.IDLE

@Synchronized

override fun startRecording(recorderConfig: RecorderConfig): String {

try {

mMediaRecorder = MediaRecorder()

mMediaRecorder?.setAudioSource(recorderConfig.audioSource)

when (recorderConfig.recorderOutFormat) {

RecorderOutFormat.MPEG_4 -> {

mMediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)

mMediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)

}

RecorderOutFormat.AMR_WB -> {

mMediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB)

mMediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB)

}

else -> {

mMediaRecorder?.reset()

mMediaRecorder?.release()

mMediaRecorder = null

return “MediaRecorder 不支持 AudioFormat.PCM”

}

}

} catch (e: IllegalStateException) {

mMediaRecorder?.reset()

mMediaRecorder?.release()

mMediaRecorder = null

return “Error initializing media recorder 初始化失败”;

}

return try {

val file = recorderConfig.recorderFile

file.parentFile.mkdirs()

file.createNewFile()

val outputPath: String = file.absolutePath

mMediaRecorder?.setOutputFile(outputPath)

mMediaRecorder?.prepare()

mMediaRecorder?.start()

mState = RecorderState.RECORDING

“”

} catch (e: Exception) {

mMediaRecorder?.reset()

mMediaRecorder?.release()

mMediaRecorder = null

recorderConfig.recorderFile.delete()

e.toString()

}

}

override fun isRecording(): Boolean {

return mState == RecorderState.RECORDING

}

@Synchronized

override fun stopRecording() {

try {

if (mState == RecorderState.RECORDING) {

mMediaRecorder?.stop()

mMediaRecorder?.reset()

mMediaRecorder?.release()

}

} catch (e: java.lang.IllegalStateException) {

e.printStackTrace()

}

mMediaRecorder = null

mState = RecorderState.IDLE

}

override fun state(): RecorderState {

return mState

}

}

这里需要注意的就是加 @Synchronized因为多进程同时调用的时候会出现状态错乱问题,需要加上才安全。

AIDL 接口定义

interface IRecorderService {

void startRecording(in RecorderConfig recorderConfig);

void stopRecording(in RecorderConfig recorderConfig);

boolean isRecording(in RecorderConfig recorderConfig);

RecorderResult getActiveRecording();

void registerCallback(IRecorderCallBack callBack);

void unregisterCallback(IRecorderCallBack callBack);

}

注意点:

  • 自定义参数需要实现Parcelable接口

  • 需要回调的话也是AIDL接口定义

AIDL 接口回调定义

interface IRecorderCallBack {

void onStart(in RecorderResult result);

void onStop(in RecorderResult result);

void onException(String error,in RecorderResult result);

}

RecorderService 实现

接下来就是功能的核心,跨进程的服务

class RecorderService : Service() {

private var iRecorder: IRecorder? = null

private var currentRecorderResult: RecorderResult = RecorderResult()

private var currentWeight: Int = -1

private val remoteCallbackList: RemoteCallbackList = RemoteCallbackList()

private val mBinder: IRecorderService.Stub = object : IRecorderService.Stub() {

override fun startRecording(recorderConfig: RecorderConfig) {

startRecordingInternal(recorderConfig)

}

override fun stopRecording(recorderConfig: RecorderConfig) {

if (recorderConfig.recorderId == currentRecorderResult.recorderId)

stopRecordingInternal()

else {

notifyCallBack {

it.onException(

“Cannot stop the current recording because the recorderId is not the same as the current recording”,

currentRecorderResult

)

}

}

}

override fun getActiveRecording(): RecorderResult? {

return currentRecorderResult

}

override fun isRecording(recorderConfig: RecorderConfig?): Boolean {

return if (recorderConfig?.recorderId == currentRecorderResult.recorderId)

iRecorder?.isRecording ?: false

else false

}

override fun registerCallback(callBack: IRecorderCallBack) {

remoteCallbackList.register(callBack)

}

override fun unregisterCallback(callBack: IRecorderCallBack) {

remoteCallbackList.unregister(callBack)

}

}

override fun onBind(intent: Intent?): IBinder? {

return mBinder

}

@Synchronized

private fun startRecordingInternal(recorderConfig: RecorderConfig) {

val willStartRecorderResult =

RecorderResultBuilder.aRecorderResult().withRecorderFile(recorderConfig.recorderFile)

.withRecorderId(recorderConfig.rec

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

orderId).build()

if (ContextCompat.checkSelfPermission(

this@RecorderService,

android.Manifest.permission.RECORD_AUDIO

)

!= PackageManager.PERMISSION_GRANTED

) {

logD(“Record audio permission not granted, can’t record”)

notifyCallBack {

it.onException(

“Record audio permission not granted, can’t record”,

willStartRecorderResult

)

}

return

}

if (ContextCompat.checkSelfPermission(

this@RecorderService,

android.Manifest.permission.WRITE_EXTERNAL_STORAGE

)

!= PackageManager.PERMISSION_GRANTED

) {

logD(“External storage permission not granted, can’t save recorded”)

notifyCallBack {

it.onException(

“External storage permission not granted, can’t save recorded”,

willStartRecorderResult

)

}

return

}

if (isRecording()) {

val weight = recorderConfig.weight

if (weight < currentWeight) {

logD(“Recording with weight greater than in recording”)

notifyCallBack {

it.onException(

“Recording with weight greater than in recording”,

willStartRecorderResult

)

}

return

}

if (weight > currentWeight) {

//只要权重大于当前权重,立即停止当前。

stopRecordingInternal()

}

if (weight == currentWeight) {

if (recorderConfig.recorderId == currentRecorderResult.recorderId) {

notifyCallBack {

it.onException(

“The same recording cannot be started repeatedly”,

willStartRecorderResult

)

}

return

} else {

stopRecordingInternal()

}

}

startRecorder(recorderConfig, willStartRecorderResult)

} else {

startRecorder(recorderConfig, willStartRecorderResult)

}

}

private fun startRecorder(

recorderConfig: RecorderConfig,

willStartRecorderResult: RecorderResult

) {

logD(“startRecording result ${willStartRecorderResult.toString()}”)

iRecorder = when (recorderConfig.recorderOutFormat) {

RecorderOutFormat.MPEG_4, RecorderOutFormat.AMR_WB -> {

JLMediaRecorder()

}

RecorderOutFormat.PCM -> {

JLAudioRecorder()

}

}

val result = iRecorder?.startRecording(recorderConfig)

if (!result.isNullOrEmpty()) {

logD(“startRecording result $result”)

notifyCallBack {

it.onException(result, willStartRecorderResult)

}

} else {

currentWeight = recorderConfig.weight

notifyCallBack {

it.onStart(willStartRecorderResult)

}

currentRecorderResult = willStartRecorderResult

}

}

private fun isRecording(): Boolean {

return iRecorder?.isRecording ?: false

}

@Synchronized

private fun stopRecordingInternal() {

logD(“stopRecordingInternal”)

iRecorder?.stopRecording()

currentWeight = -1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值