Android 一次完美的跨进程服务共享实践,android 图书管理系统源码
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<IRecorderCallBack> = 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.recorderId).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")
notify
CallBack {
it.onException(result, willStartRecorderResult)
}
} else {
评论