Android完美实现录音编辑器
- 一、目标
- 二、准备工作
- 三、功能分析
- 四、实现过程
- 五、一些技术问题
- 1. MediaPlayer
- 2. Chronometer
- 3. 保持屏幕长亮
- 4. 关闭编辑器
- 六、开发过程回顾
- 七、接下来
- 八、Finally
一、目标
实现录音编辑器,为神马笔记增加录音功能做准备。
二、准备工作
序号 | 准备工作 | 描述 |
---|
1 | Android实现录音功能汇总 | 全面了解Android实现录音功能的各种方式,并且比较方式的优劣,最终选择MediaRecorder来实现录音。 |
2 | Android低仿iOS Messages录音波形效果 | 使用MediaRecorder实现录音,并封装成TapeRecordView方便调用。 |
3 | Android高仿iOS Messages声音播放波形效果 | 使用MediaPlayer播放录音,并封装成TapePlayView方便调用。 |
4 | Android高仿iOS Messages录音操作按钮 | 实现ActionLayout作为滑动按钮。 |
5 | Android使用PopupWindow高仿iOS Messages录音弹出界面 | 选择录音编辑器的容器,比较了Activity、Dialog、PopupWindow、FrameLayout,并选择PopupWindow作为容器。 |
通过5个阶段的准备工作,解决了录音相关的所有技术问题。
最后一步便是把所有功能组合到一起。
三、功能分析
1. 界面组成
整个录音编辑器界面分为2个部分。
- 波形
- 操作
界面组成 | 控件组成 |
---|
波形 | 关闭按钮 |
| 录音波形、播放波形 |
| 时间显示 |
| |
操作 | 发送按钮 |
| 停止录音、播放录音,暂停播放 |
2. 事件处理
事件 | 触发条件 | 处理方式 |
---|
布局变化 | 通常情况下,布局不会发生变化。 长按电源键或者来电时,会隐藏软键盘,从而引起布局变化。 | 调整编辑器位置。 |
切换到后台 | 用户按下多任务键或者Home键,或者来电时,将应用切换到后台。 | 停止录音、停止播放 |
截图 | 描述 |
---|
| 长按电源键,将会隐藏软键盘。 |
四、实现过程
序号 | 过程 |
---|
1 | 定义PopupTape 作为编辑器类,并实现show 方法以显示界面 |
| |
2 | 实现录音及停止功能 |
3 | 实现播放及暂停功能 |
4 | 显示录音及播放时间进度 |
| |
5 | 实现关闭功能,通过关闭按钮以及用户按下返回键 |
| |
6 | 处理dispatchTouchEvent事件,实现弹出界面后可以继续操作。 |
7 | 处理onGlobalLayout事件,对编辑器重新布局。 |
8 | 处理onStop事件,切换到后台时自动停止录音及播放。 |
| |
9 | 增加对外事件回调接口BiConsumer,用于告知用户操作结果。 |
10 | 增加属性访问接口,以插叙PopupTape属性。 |
五、一些技术问题
1. MediaPlayer
MediaPlayer播放过程中,调用getCurrentPosition
方法获取当前播放进度。
出现时间回退的情况,出现在250毫秒~300毫秒之间。
导致了绘制波形时,出现闪烁的情况。
int current = mMediaPlayer.getCurrentPosition();
this.currentPosition = (current > this.currentPosition)? current: this.currentPosition;current = this.currentPosition;
增加一个变量用于跟踪进度,防止回退。
2. Chronometer
使用Chronometer
显示播放进度时,出现时间跳动的情况。
Chronometer
虽然1秒回调一次,但并不是严格的1000毫秒,因此会出现累加的误差,最终导致时间跳动。
自定义Chronotimer
,采用每帧刷新的方式保证时间的准确性。
public class Chronotimer extends androidx.appcompat.widget.AppCompatTextView {boolean isRunning = false;long base = 0; long start; long end; PreDrawListener preDrawListener;private boolean mPreDrawRegistered;public Chronotimer(Context context) {this(context, null);}public Chronotimer(Context context, @Nullable AttributeSet attrs) {this(context, attrs, android.R.attr.textViewStyle);}public Chronotimer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.preDrawListener = new PreDrawListener();}public void start() {this.isRunning = true;this.start = System.currentTimeMillis();this.end = start;this.registerForPreDraw();this.invalidate();}public void stop() {this.isRunning = false;this.end = System.currentTimeMillis();this.unregisterForPreDraw(); this.invalidate();}public void setBase(long base) {this.base = base;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();if (isRunning) {registerForPreDraw();}}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();this.unregisterForPreDraw();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (isRunning) {this.invalidate();}}public CharSequence format(long milliseconds) {long elapse = milliseconds;elapse /= 1000; int hours = (int)(elapse / 3600);int seconds = (int)(elapse % 3600);int minute = (seconds / 60);seconds = seconds % 60;String text;if (hours > 0) {text = String.format("%d:%02d:%02d", hours, minute, seconds);} else {text = String.format("%d:%02d", minute, seconds);}return text;}private void registerForPreDraw() {if (!mPreDrawRegistered) {getViewTreeObserver().addOnPreDrawListener(preDrawListener);mPreDrawRegistered = true;}}private void unregisterForPreDraw() {getViewTreeObserver().removeOnPreDrawListener(preDrawListener);mPreDrawRegistered = false;}private class PreDrawListener implements ViewTreeObserver.OnPreDrawListener {@Overridepublic boolean onPreDraw() {if (isRunning) {end = System.currentTimeMillis();}long duration = (end - start);duration += base;CharSequence text = format(duration);setText(text);return true;}}
}
3. 保持屏幕长亮
为防止锁屏自动停止录音,因此保证录音过程中屏幕长亮。
4. 关闭编辑器
与iOS Messages点击操作按钮外部区域管理编辑器不同。
必须点击关闭按钮才能关闭编辑器。
iOS Messages是聊天工具,录音内容通常较短。
神马笔记是笔记工具,用户可能进行长时间录音。
为防止用户误操作关闭编辑器,因此采用关闭按钮的方式。
六、开发过程回顾
集合了前面的所有功能,终于完成录音编辑器。
高仿了iOS Messages的录音功能:)
效果还算满意。
七、接下来
完成录音显示,及RecyclerView中多个录音的播放功能。
为神马笔记实现录音笔记元素做准备。
八、Finally
佛说是经已。
长老须菩提。
及诸比丘。比丘尼。
优婆塞。优婆夷。
一切世间天人阿修罗。
闻佛所说。皆大欢喜。信受奉行。