服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - android MediaRecorder实现录屏时带录音功能

android MediaRecorder实现录屏时带录音功能

2022-12-07 14:10不再皱眉 Android

这篇文章主要介绍了android MediaRecorder录屏时带录音功能实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

下面说说android的事把

最近是不是也会遇到需求中需要用到录屏录音的功能,最近也是遇到的 现在整理完记录一下

首先呢,录音录屏需要权限 先贴一个动态权限类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TalAllow {
  /**
   * RECORD_AUDIO     音频权限
   * WRITE_EXTERNAL_STORAGE 写入权限
   * CAMERA        相机权限
   */
  public static void requestPermissions(Context context,int allowCode) {
    ArrayList<String> ps = new ArrayList<>();
    int per = ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.RECORD_AUDIO);
    }
    per = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    per = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.CAMERA);
    }
    per = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE);
    if (per != PackageManager.PERMISSION_GRANTED) {
      ps.add(Manifest.permission.READ_PHONE_STATE);
    }
    Log.d(TAG, "requestPermissions:ps=" + ps.size());
    if (!ps.isEmpty()) {
      String[] ps3 = new String[ps.size()];
      ps.toArray(ps3);
      ActivityCompat.requestPermissions((Activity) context, ps3, allowCode);
    }
  }
}

有需求需要判断权限的呢 插入个链接 (上面那个类code码为100)
判断是否有权限

下面重点来了

首先说明一下这个录屏和录音是在服务里面做的,所以呢贴一个服务类
这个代码绝对有质量 做了很多处理,下面一行一行解读把

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//首先呢实现的是Handle.Callback接口 主要是做时间及计时时间回调的,会重新写HandleMessage方法,其实我个觉得跟在括号{} 里面重写没啥区别就是简洁页面
public class TalScreenRecordService extends Service implements Handler.Callback {
//这个就不解释了吧 log
  private static final String TAG = "TalScreenRecordService";
  //这个类是管理类拿到服务后会通过下面的类申请录屏,点击允许,
  //其中会回调两个参数,code码 和 data,都在ActivityForResult中进行判断code
  private MediaProjectionManager mProjectionManager;
 //这个会拿到申请的结果
  private MediaProjection mMediaProjection;
  //这个类就是我们主要的录屏录音的类啦
  private MediaRecorder mMediaRecorder;
  //这个就是我们要获取录制屏幕的大小,像素,等等一些数据
  //关于这类更详细的介绍https://blog.csdn.net/qq_16628781/article/details/62038163
  private VirtualDisplay mVirtualDisplay;
 //是否正在录制 false 没有录制
  private boolean mIsRunning;
  //获取屏幕的宽高和像素密度 稍后贴类
  private int mRecordWidth = TalScreenParams.getScreenWidth();
  private int mRecordHeight = TalScreenParams.getScreenWidth();
  private int mScreenDpi = TalScreenParams.getScreenDpi();
 //code data 就是上面说的允许后回调
  private int mResultCode;
  private Intent mResultData;
  //录屏文件的保存地址
  private String mRecordFilePath;
  private Handler mHandler;
  //已经录制多少秒了
  private int mRecordSeconds = 0;
  //handle发送消息时的what
  private static final int MSG_TYPE_COUNT_DOWN = 110;
 //这个是继承Service 必须重写的方法 这是使用的BindService(生命周期的长短跟activity一致)
  @Override
  public IBinder onBind(Intent intent) {
    return new RecordBinder();
  }
 //说一说这个返回值的问题吧
 // START_STICKY 粘性返回 ,一次失败,多次启动,不保留Intent对象
 //关于返回值问题https://blog.csdn.net/github_37663523/article/details/78811539
 @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    return START_STICKY;
  }
  @Override
  public void onCreate() {
    super.onCreate();
    //没有录制
    mIsRunning = false;
    //创建对象 在create方法里只执行一次
    mMediaRecorder = new MediaRecorder();
    // 由于实现了CallBack接口,在这里注册一下接口(个人觉得高大的写法,简洁)
    mHandler = new Handler(Looper.getMainLooper(), this);
  }
  @Override
  public void onDestroy() {
    super.onDestroy();
  }
 //数据不为空
  public boolean isReady() {
    return mMediaProjection != null && mResultData != null;
  }
 //清除的方法 避免内存泄漏 相信都看得懂
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public void clearRecordElement() {
    clearAll();
    if (mMediaRecorder != null) {
      mMediaRecorder.reset();
      mMediaRecorder.release();
      mMediaRecorder = null;
    }
    mResultData = null;
    //不执行的时候false
    mIsRunning = false;
  }
 //这个就是给是否正在录屏提供一个get方法
  public boolean ismIsRunning() {
    return mIsRunning;
  }
 //这个就是设置数据的方法在ActivityForResult中设置数据,说明是允许录屏的
  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public void setResultData(int resultCode, Intent resultData) {
    mResultCode = resultCode;
    mResultData = resultData;
 //拿到这个管理,看不懂跟上面注释结合看
    mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    //getMediaProjection(code,data)不知道这样写看不看的董
    //说白了MediaProjectionManager是申请权限 MediaProjection是获取申请结果,防止别人调取隐私
    //再通过上面的setResultData方法获取到ActivityForResult中的code,data
    if (mProjectionManager != null) {
      mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData);
    }
  }
 //开始录制了
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public boolean startRecord() {
  //代码执行顺序(false,目前没录屏)
    if (mIsRunning) {
      return false;
    }
    //再次创建,防止异常
    if (mMediaProjection == null) {
      mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData);
    }
 //关于文件路径还有录屏的一些参数问题
    setUpMediaRecorder();
    //关于获取录制屏幕的大小,像素,等等一些数据
    createVirtualDisplay();
    //开始录制
    mMediaRecorder.start();
 //稍后贴类 监听录制情况
    TalScreenUtils.startRecord();
    //最多录制三分钟
    mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN, 1000);
    //录制时为true
    mIsRunning = true;
    Log.d(TAG, "startRecord ");
    return true;
  }
 //停止的方法
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public boolean stopRecord(String tip) {
    Log.d(TAG, "stopRecord: first ");
    //mIsRunning 默认值为false !mIsRunning 就是true。。
    if (!mIsRunning) {
      return false;
    }
    mIsRunning = false;
    Log.w(TAG, "stopRecord middle");
    try {
    //停止抓取异常,该置空的为空
      mMediaRecorder.stop();
      mMediaRecorder.reset();
      mMediaRecorder = null;
      mVirtualDisplay.release();
      mMediaProjection.stop();
      Log.w(TAG, "stopRecord ");
    } catch (Exception e) {
      e.printStackTrace();
      mMediaRecorder.release();
      mMediaRecorder = null;
      Log.w(TAG, "stopRecord exception");
    }
    mMediaProjection = null;
 //停止时移出这条消息what
    mHandler.removeMessages(MSG_TYPE_COUNT_DOWN);
    //停止的监听 tip 是处理一些突发情况 比如内存不足
    TalScreenUtils.stopRecord(tip);
    Log.i(TAG, "stopRecord: " + mRecordFilePath);
    //录制时间不到两秒就删除录制文件
    if (mRecordSeconds <= 2) {
      TalFileUtils.deleteSDFile(mRecordFilePath);
    } else {
    //录制的视频库,将数据添加到媒体库
    //这个算是应用程序之间共享数据,把自己应用的数据添加到手机的媒体库ContentResolver
    //举个例子,代码添加手机联系人到自己的联系人列表,或者代码添加图片到自己的图库,还有不懂得,贴个链接
    //https://blog.csdn.net/bzlj2912009596/article/details/80248272
      TalFileUtils.fileScanVideo(this, mRecordFilePath, 1280, 720, mRecordSeconds);
    }
//    mRecordFilePath = null;
    mRecordSeconds = 0;
    return true;
  }
 //下面是关于处理在一些activity or fragment中生命周期的做法
  public void pauseRecord() {
    if (mMediaRecorder != null) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mMediaRecorder.pause();
      }
    }
  }
  public void resumeRecord() {
    if (mMediaRecorder != null) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        mMediaRecorder.resume();
      }
    }
  }
 //这个就是刚才讲过的 绘制窗口大小,dpi问题 VirtualDisplay
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  private void createVirtualDisplay() {
    mVirtualDisplay = mMediaProjection.createVirtualDisplay("MainScreen", 1280, 720, mScreenDpi,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
  }
 //这个主要是路径,还有设置一些录制视频参数问题separator 为字节,占位用
  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  private void setUpMediaRecorder() {
    mRecordFilePath = getSaveDirectory() + File.separator + System.currentTimeMillis() + ".mp4";
    Log.i(TAG, "setUpMediaRecorder: " + mRecordFilePath);
    if (mMediaRecorder == null) {
      mMediaRecorder = new MediaRecorder();
    }
    //设置音频源
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 //设置视频源   
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
 //设置输出的编码格式
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    if (mRecordFilePath != null) {
      mMediaRecorder.setOutputFile(mRecordFilePath);
    } else if (mRecordFilePath == null) {
      mMediaRecorder.setOutputFile(mRecordFilePath);
    }
    //设置录屏时屏幕大小,这个可跟mVirtualDisplay 一起控制屏幕大小
    //mVirtualDisplay 是将屏幕设置成多大多小,setVideoSize是输出文件时屏幕多大多小
    mMediaRecorder.setVideoSize(1280, 720);
     //图像编码 H264较好还有其他选择
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
  //音频编码   
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    //设置码率 高清的话的要数越大
    mMediaRecorder.setVideoEncodingBitRate((int) (1280 * 720 * 2.6));
    //设置帧率,该帧率必须是硬件支持的,可以通过Camera.CameraParameter.getSupportedPreviewFpsRange()方法获取相机支持的帧率
    mMediaRecorder.setVideoFrameRate(20);
    try {
    //准备
      mMediaRecorder.prepare();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  public void clearAll() {
    if (mMediaProjection != null) {
      mMediaProjection.stop();
      mMediaProjection = null;
    }
  }
 //路径
  public String getRecordFilePath() {
    return mRecordFilePath;
  }
 //sd下绝对路径,先判断sd卡是否挂载
  public String getSaveDirectory() {
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
      return Environment.getExternalStorageDirectory().getAbsolutePath();
    } else {
      return null;
    }
  }
  //这是实现了Handle.CallBack中重写方法 handleMessage
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  @Override
  public boolean handleMessage(Message msg) {
    switch (msg.what) {
      case MSG_TYPE_COUNT_DOWN: {
        String str = null;
        //这是内存
        boolean enough = TalFileUtils.getSDFreeMemory() / (1024 * 1024) < 4;
        if (enough) {
          //空间不足,停止录屏
          str = "空间不足";
          //停止录屏时 通过接口回调一个信息,是因为什么停止录屏的
          stopRecord(str);
          mRecordSeconds = 0;
          break;
        }
        mRecordSeconds++;
        int minute = 0, second = 0;
        if (mRecordSeconds >= 60) {
          minute = mRecordSeconds / 60;
          second = mRecordSeconds % 60;
        } else {
          second = mRecordSeconds;
        }
        TalScreenUtils.onRecording("0" + minute + ":" + (second < 10 ? "0" + second : second + ""));
        if (mRecordSeconds < 5 * 60) {
          mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN, 1000);
        } else if (mRecordSeconds == 5 * 60) {
          str = "录制已到限定时长";
          stopRecord(str);
          mRecordSeconds = 0;
        }
        break;
      }
    }
    return true;
  }
  public class RecordBinder extends Binder {
    public TalScreenRecordService getRecordService() {
      return TalScreenRecordService.this;
    }
  }
}

下面贴关于手机像素还有dpi的类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class TalScreenParams {
  private static int mScreenWidth;
  private static int mScreenHeight;
  private static int mScreenDpi;
 
  public static void init(Activity activity){
    Display display = activity.getWindowManager().getDefaultDisplay();
    DisplayMetrics metrics = new DisplayMetrics();
    display.getMetrics(metrics);
    mScreenWidth = metrics.widthPixels;
    mScreenHeight = metrics.heightPixels;
    mScreenDpi = metrics.densityDpi;
  }
 
  public static int getScreenWidth(){
    return mScreenWidth;
  }
 
  public static int getScreenHeight(){
    return mScreenHeight;
  }
 
  public static int getScreenDpi(){
    return mScreenDpi;
  }

下面贴关于删除文件,添加到媒体库的类 这里就使用到了ContentResolver

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
public class TalFileUtils {
  /**
   * 删除SD卡中的文件或目录
   *
   * @param path
   * @return
   */
  public static boolean deleteSDFile(String path) {
    return deleteSDFile(path, false);
  }
 
  /**
   * 删除SD卡中的文件或目录
   *
   * @param path
   * @param deleteParent true为删除父目录
   * @return
   */
  public static boolean deleteSDFile(String path, boolean deleteParent) {
    if (TextUtils.isEmpty(path)) {
      return false;
    }
 
    File file = new File(path);
    if (!file.exists()) {
      //不存在
      return true;
    }
    return deleteFile(file, deleteParent);
  }
 
  /**
   * @param file
   * @param deleteParent true为删除父目录
   * @return
   */
  public static boolean deleteFile(File file, boolean deleteParent) {
    boolean flag = false;
    if (file == null) {
      return flag;
    }
    if (file.isDirectory()) {
      //是文件夹
      File[] files = file.listFiles();
      if (files.length > 0) {
        for (int i = 0; i < files.length; i++) {
          flag = deleteFile(files[i], true);
          if (!flag) {
            return flag;
          }
        }
      }
      if (deleteParent) {
        flag = file.delete();
      }
    } else {
      flag = file.delete();
    }
    file = null;
    return flag;
  }
 
  /**
   * 添加到媒体数据库
   *
   * @param context 上下文
   */
  public static Uri fileScanVideo(Context context, String videoPath, int videoWidth, int videoHeight,
                  int videoTime) {
    File file = new File(videoPath);
    if (file.exists()) {
      Uri uri = null;
      long size = file.length();
      String fileName = file.getName();
      long dateTaken = System.currentTimeMillis();
      ContentValues values = new ContentValues(11);
      values.put(MediaStore.Video.Media.DATA, videoPath); // 路径;
      values.put(MediaStore.Video.Media.TITLE, fileName); // 标题;
      values.put(MediaStore.Video.Media.DURATION, videoTime * 1000); // 时长
      values.put(MediaStore.Video.Media.WIDTH, videoWidth); // 视频宽
      values.put(MediaStore.Video.Media.HEIGHT, videoHeight); // 视频高
      values.put(MediaStore.Video.Media.SIZE, size); // 视频大小;
      values.put(MediaStore.Video.Media.DATE_TAKEN, dateTaken); // 插入时间;
      values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);// 文件名;
      values.put(MediaStore.Video.Media.DATE_MODIFIED, dateTaken / 1000);// 修改时间;
      values.put(MediaStore.Video.Media.DATE_ADDED, dateTaken / 1000); // 添加时间;
      values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
 
      ContentResolver resolver = context.getContentResolver();
 
      if (resolver != null) {
        try {
          uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
        } catch (Exception e) {
          e.printStackTrace();
          uri = null;
        }
      }
 
      if (uri == null) {
        MediaScannerConnection.scanFile(context, new String[]{videoPath}, new String[]{"video/*"}, new MediaScannerConnection.OnScanCompletedListener() {
          @Override
          public void onScanCompleted(String path, Uri uri) {
 
          }
        });
      }
 
      return uri;
    }
 
    return null;
  }
 
  /**
   * SD卡存在并可以使用
   */
  public static boolean isSDExists() {
    return Environment.getExternalStorageState().equals(
        Environment.MEDIA_MOUNTED);
  }
 
  /**
   * 获取SD卡的剩余容量,单位是Byte
   *
   * @return
   */
  public static long getSDFreeMemory() {
    try {
      if (isSDExists()) {
        File pathFile = Environment.getExternalStorageDirectory();
        // Retrieve overall information about the space on a filesystem.
        // This is a Wrapper for Unix statfs().
        StatFs statfs = new StatFs(pathFile.getPath());
        // 获取SDCard上每一个block的SIZE
        long nBlockSize = statfs.getBlockSize();
        // 获取可供程序使用的Block的数量
        // long nAvailBlock = statfs.getAvailableBlocksLong();
        long nAvailBlock = statfs.getAvailableBlocks();
        // 计算SDCard剩余大小Byte
        long nSDFreeSize = nAvailBlock * nBlockSize;
        return nSDFreeSize;
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return 0;
  }
  public static long getFreeMem(Context context) {
    ActivityManager manager = (ActivityManager) context.getApplicationContext().getSystemService(Activity.ACTIVITY_SERVICE);
    if (manager != null) {
      ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
      if (info != null) {
        manager.getMemoryInfo(info);
        // 单位Byte
        return info.availMem / 1024 / 1024;
      }
    }
    return 0;
  }
}

还有一个类 是为整个Service提供了便捷访问的类 ,将一些监听service中的变化放到集合里来做

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
public class TalScreenUtils {
  private static TalScreenRecordService s_ScreenRecordService;
  private static List<RecordListener> s_RecordListener = new ArrayList<>();
  private static List<OnPageRecordListener> s_PageRecordListener = new ArrayList<>();
  //true,录制结束的提示语正在显示
  public static boolean s_IsRecordingTipShowing = false;
  /**
   * 录屏功能 5.0+ 的手机才能使用
   * @return
   */
  public static boolean isScreenRecordEnable(){
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ;
  }
  public static void setScreenService(TalScreenRecordService screenService){
    s_ScreenRecordService = screenService;
  }
  public static void clear(){
    if ( isScreenRecordEnable() && s_ScreenRecordService != null){
      s_ScreenRecordService.clearAll();
      s_ScreenRecordService = null;
    }
    if (s_RecordListener != null && s_RecordListener.size() > 0){
      s_RecordListener.clear();
    }
    if (s_PageRecordListener != null && s_PageRecordListener.size() > 0 ){
      s_PageRecordListener.clear();
    }
  }
  /**
   * 开始录制
   */
  public static void startScreenRecord(Activity activity, int requestCode) {
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null && !s_ScreenRecordService.ismIsRunning()){
        if (!s_ScreenRecordService.isReady()){
          MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity.
              getSystemService(Context.MEDIA_PROJECTION_SERVICE);
          if (mediaProjectionManager != null){
            Intent intent = mediaProjectionManager.createScreenCaptureIntent();
            PackageManager packageManager = activity.getPackageManager();
            if (packageManager.resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY) != null){
              //存在录屏授权的Activity
              activity.startActivityForResult(intent,requestCode);
            }else {
              Toast.makeText(activity, "不能录音", Toast.LENGTH_SHORT).show();
            }
          }
        } else {
          s_ScreenRecordService.startRecord();
        }
      }
    }
  }
  /**
   * 获取用户允许录屏后,设置必要的数据
   * @param resultCode
   * @param resultData
   */
  public static void setUpData(int resultCode,Intent resultData) throws Exception{
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null && !s_ScreenRecordService.ismIsRunning()){
        s_ScreenRecordService.setResultData(resultCode,resultData);
        s_ScreenRecordService.startRecord();
      }
    }
  }
  /**
   * 停止录制
   */
  public static void stopScreenRecord(Context context){
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null && s_ScreenRecordService.ismIsRunning()){
        String str = "停止录制";
        s_ScreenRecordService.stopRecord(str);
      }
    }
  }
  /**
   * 获取录制后的文件地址
   * @return
   */
  public static String getScreenRecordFilePath(){
    if (isScreenRecordEnable() && s_ScreenRecordService!= null) {
      return s_ScreenRecordService.getRecordFilePath();
    }
    return null;
  }
  /**
   * 判断当前是否在录制
   * @return
   */
  public static boolean isCurrentRecording(){
    if (isScreenRecordEnable() && s_ScreenRecordService!= null) {
      return s_ScreenRecordService.ismIsRunning();
    }
    return false;
  }
  /**
   * true,录制结束的提示语正在显示
   * @return
   */
  public static boolean isRecodingTipShow(){
    return s_IsRecordingTipShowing;
  }
  public static void setRecordingStatus(boolean isShow){
    s_IsRecordingTipShowing = isShow;
  }
  /**
   * 系统正在录屏,app 录屏会有冲突,清理掉一些数据
   */
  public static void clearRecordElement(){
    if (isScreenRecordEnable()){
      if (s_ScreenRecordService != null ){
        s_ScreenRecordService.clearRecordElement();
      }
    }
  }
  public static void addRecordListener(RecordListener listener){
    if (listener != null && !s_RecordListener.contains(listener)){
      s_RecordListener.add(listener);
    }
  }
  public static void removeRecordListener(RecordListener listener){
    if (listener != null && s_RecordListener.contains(listener)){
      s_RecordListener.remove(listener);
    }
  }
  public static void addPageRecordListener( OnPageRecordListener listener){
    if (listener != null && !s_PageRecordListener.contains(listener)){
      s_PageRecordListener.add(listener);
    }
  }
  public static void removePageRecordListener( OnPageRecordListener listener){
    if (listener != null && s_PageRecordListener.contains(listener)){
      s_PageRecordListener.remove(listener);
    }
  }
  public static void onPageRecordStart(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onStartRecord();
      }
    }
  }
  public static void onPageRecordStop(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onStopRecord();
      }
    }
  }
  public static void onPageBeforeShowAnim(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onBeforeShowAnim();
      }
    }
  }
  public static void onPageAfterHideAnim(){
    if (s_PageRecordListener!= null && s_PageRecordListener.size() > 0 ){
      for (OnPageRecordListener listener : s_PageRecordListener){
        listener.onAfterHideAnim();
      }
    }
  }
  public static void startRecord(){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onStartRecord();
        Log.i("xxx", "startRecord: ");
      }
    }
  }
  public static void pauseRecord(){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onPauseRecord();
      }
    }
  }
  public static void resumeRecord(){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onResumeRecord();
      }
    }
  }
  public static void onRecording(String timeTip){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onRecording(timeTip);
      }
    }
  }
  public static void stopRecord(String stopTip){
    if (s_RecordListener.size() > 0 ){
      for (RecordListener listener : s_RecordListener){
        listener.onStopRecord( stopTip);
      }
    }
  }
  public interface RecordListener{
    void onStartRecord();
    void onPauseRecord();
    void onResumeRecord();
    void onStopRecord(String stopTip);
    void onRecording(String timeTip);
  }
  public interface OnPageRecordListener {
    void onStartRecord();
    void onStopRecord();
    void onBeforeShowAnim();
    void onAfterHideAnim();
  }
}

到了最后了,是一些调用时的内容

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
public class MainActivity extends AppCompatActivity {
  private static final String TAG = MainActivity.class.getSimpleName();
  private Button mBtn;
  private final int REQUEST_ALLOW = 100;
  private Button mButton;
  //bindService需要创建连接
  private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      //启动service
      TalScreenRecordService.RecordBinder recordBinder = (TalScreenRecordService.RecordBinder) service;
      TalScreenRecordService recordService = recordBinder.getRecordService();
      //这个其实是传值在使用的activity中拿到Service
      TalScreenUtils.setScreenService(recordService);
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
  };
 //开启service,意图跳转到service,别忘了AndroidManifest里面需要注册这个service哦
  private void startService() {
    Intent intent = new Intent(MainActivity.this, TalScreenRecordService.class);
    bindService(intent, mConnection, BIND_AUTO_CREATE);
  }
  @Override
  protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mBtn = findViewById(R.id.btn);
    mButton = findViewById(R.id.button2);
    initView();
    //两个按钮 一个开始 一个结束 xml不贴了
    mBtn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if (TalFileUtils.getFreeMem(MainActivity.this) < 100) {
          Toast.makeText(MainActivity.this, "手机内存不足,请清理后再进行录屏", Toast.LENGTH_SHORT).show();
          return;
        }
        //开始录屏录音
        TalScreenUtils.startScreenRecord(MainActivity.this, REQUEST_ALLOW);
      }
    });
    mButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        stop();
        Log.i(TAG, "onClick: " + stop());
      }
  //停止录屏录音返回路径
      private String stop() {
        TalScreenUtils.stopScreenRecord(MainActivity.this);//停止
        return TalScreenUtils.getScreenRecordFilePath();
      }
    });
  }
  @Override
  protected void onStart() {
    super.onStart();
 
  }
 
  private void initView() {
    //权限申请
    TalAllow.requestPermissions(this, REQUEST_ALLOW);
    //获取屏幕大小 在onCreate里面初始化就可以获取
    TalScreenParams.init(this);
    startService();
  }
 
  @Override
  protected void onStop() {
    super.onStop();
    //在对用户可见不可交互的时候防止异常
    TalScreenUtils.clear();
  }
 //打印权限获取情况日志
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Toast.makeText(this, permissions[0] + "\n" + grantResults[0], Toast.LENGTH_SHORT).show();
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  }
 //在用户允许录屏后拿到确定的code 跟data
  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_ALLOW && data != null) {
      try {
      //设置数据,在用户允许后 调用了开始录屏的方法
        TalScreenUtils.setUpData(resultCode, data);
        //拿到路径
        String screenRecordFilePath = TalScreenUtils.getScreenRecordFilePath();
        if (screenRecordFilePath == null) {
          Toast.makeText(this, "空的", Toast.LENGTH_SHORT).show();
        }
        Toast.makeText(MainActivity.this, "" + screenRecordFilePath, Toast.LENGTH_SHORT).show();
        Log.i("zlq", "onClick: " + screenRecordFilePath);
      } catch (Exception e) {
        e.printStackTrace();
      }
    } else {
      Toast.makeText(this, "禁止录屏", Toast.LENGTH_SHORT).show();
    }
  }
 
  @Override
  protected void onDestroy() {
    super.onDestroy();
    unbindService(mConnection);
  }
}

至此,一个还算比较完整的录屏录音功能就可以实现,不足之处请批评指正

总结

到此这篇关于android MediaRecorder录屏时带录音功能实现的文章就介绍到这了,更多相关android MediaRecorder录屏带录音内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/HelloJavaString/article/details/105318287

延伸 · 阅读

精彩推荐