android MediaRecorder实现录屏时带录音功能
下面说说android的事把
最近是不是也会遇到需求中需要用到录屏录音的功能,最近也是遇到的 现在整理完记录一下
首先呢,录音录屏需要权限 先贴一个动态权限类
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)
判断是否有权限
下面重点来了
首先说明一下这个录屏和录音是在服务里面做的,所以呢贴一个服务类
这个代码绝对有质量 做了很多处理,下面一行一行解读把
//首先呢实现的是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的类
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
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中的变化放到集合里来做
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(); } }
到了最后了,是一些调用时的内容
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录屏带录音内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
- Android编程录音工具类RecorderUtil定义与用法示例
- Android实现录音功能实现实例(MediaRecorder)
- Android使用AudioRecord实现暂停录音功能实例代码
- Android录音--AudioRecord、MediaRecorder的使用
- android 通过MediaRecorder实现简单的录音示例
- Android使用MediaRecorder实现录音及播放
- Android App调用MediaRecorder实现录音功能的实例
- Android音频录制MediaRecorder之简易的录音软件实现代码
- Android简单的利用MediaRecorder进行录音的实例代码
- Android使用AudioRecord实现录音功能
相关文章
Android RecyclerView四级缓存源码层详细分析
RecyclerView是Android一个更强大的控件,其不仅可以实现和ListView同样的效果,还有优化了ListView中的各种不足。其可以实现数据纵向滚动,也可以实现横向滚动(ListView做不到横向滚动)。接下来讲解RecyclerView的用法2022-11-11Android超详细介绍自定义多选框与点击按钮跳转界面的实现
这篇文章主要介绍了在Android开发中如何来实现自定义多选框以及如何实现点击按钮跳转界面的功能,感兴趣的朋友快来看看吧2022-03-03Android progressbar实现带底部指示器和文字的进度条
这篇文章主要为大家详细介绍了Android progressbar实现带底部指示器和文字的进度条,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2019-01-01
最新评论