电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

android MediaRecorder實(shí)現(xiàn)錄屏?xí)r帶錄音功能

瀏覽:88日期:2022-09-25 08:05:40

下面說(shuō)說(shuō)android的事把

最近是不是也會(huì)遇到需求中需要用到錄屏錄音的功能,最近也是遇到的 現(xiàn)在整理完記錄一下

首先呢,錄音錄屏需要權(quán)限 先貼一個(gè)動(dòng)態(tài)權(quán)限類(lèi)

public class TalAllow { /** * RECORD_AUDIO 音頻權(quán)限 * WRITE_EXTERNAL_STORAGE 寫(xiě)入權(quán)限 * CAMERA相機(jī)權(quán)限 */ 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); } }}

有需求需要判斷權(quán)限的呢 插入個(gè)鏈接 (上面那個(gè)類(lèi)code碼為100)判斷是否有權(quán)限

下面重點(diǎn)來(lái)了

首先說(shuō)明一下這個(gè)錄屏和錄音是在服務(wù)里面做的,所以呢貼一個(gè)服務(wù)類(lèi)這個(gè)代碼絕對(duì)有質(zhì)量 做了很多處理,下面一行一行解讀把

//首先呢實(shí)現(xiàn)的是Handle.Callback接口 主要是做時(shí)間及計(jì)時(shí)時(shí)間回調(diào)的,會(huì)重新寫(xiě)HandleMessage方法,其實(shí)我個(gè)覺(jué)得跟在括號(hào){} 里面重寫(xiě)沒(méi)啥區(qū)別就是簡(jiǎn)潔頁(yè)面public class TalScreenRecordService extends Service implements Handler.Callback {//這個(gè)就不解釋了吧 log private static final String TAG = 'TalScreenRecordService'; //這個(gè)類(lèi)是管理類(lèi)拿到服務(wù)后會(huì)通過(guò)下面的類(lèi)申請(qǐng)錄屏,點(diǎn)擊允許, //其中會(huì)回調(diào)兩個(gè)參數(shù),code碼 和 data,都在ActivityForResult中進(jìn)行判斷code private MediaProjectionManager mProjectionManager; //這個(gè)會(huì)拿到申請(qǐng)的結(jié)果 private MediaProjection mMediaProjection; //這個(gè)類(lèi)就是我們主要的錄屏錄音的類(lèi)啦 private MediaRecorder mMediaRecorder; //這個(gè)就是我們要獲取錄制屏幕的大小,像素,等等一些數(shù)據(jù) //關(guān)于這類(lèi)更詳細(xì)的介紹https://blog.csdn.net/qq_16628781/article/details/62038163 private VirtualDisplay mVirtualDisplay; //是否正在錄制 false 沒(méi)有錄制 private boolean mIsRunning; //獲取屏幕的寬高和像素密度 稍后貼類(lèi) private int mRecordWidth = TalScreenParams.getScreenWidth(); private int mRecordHeight = TalScreenParams.getScreenWidth(); private int mScreenDpi = TalScreenParams.getScreenDpi(); //code data 就是上面說(shuō)的允許后回調(diào) private int mResultCode; private Intent mResultData; //錄屏文件的保存地址 private String mRecordFilePath; private Handler mHandler; //已經(jīng)錄制多少秒了 private int mRecordSeconds = 0; //handle發(fā)送消息時(shí)的what private static final int MSG_TYPE_COUNT_DOWN = 110; //這個(gè)是繼承Service 必須重寫(xiě)的方法 這是使用的BindService(生命周期的長(zhǎng)短跟activity一致) @Override public IBinder onBind(Intent intent) { return new RecordBinder(); } //說(shuō)一說(shuō)這個(gè)返回值的問(wèn)題吧 // START_STICKY 粘性返回 ,一次失敗,多次啟動(dòng),不保留Intent對(duì)象 //關(guān)于返回值問(wèn)題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(); //沒(méi)有錄制 mIsRunning = false; //創(chuàng)建對(duì)象 在create方法里只執(zhí)行一次 mMediaRecorder = new MediaRecorder(); // 由于實(shí)現(xiàn)了CallBack接口,在這里注冊(cè)一下接口(個(gè)人覺(jué)得高大的寫(xiě)法,簡(jiǎn)潔) mHandler = new Handler(Looper.getMainLooper(), this); } @Override public void onDestroy() { super.onDestroy(); } //數(shù)據(jù)不為空 public boolean isReady() { return mMediaProjection != null && mResultData != null; } //清除的方法 避免內(nèi)存泄漏 相信都看得懂 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void clearRecordElement() { clearAll(); if (mMediaRecorder != null) { mMediaRecorder.reset(); mMediaRecorder.release(); mMediaRecorder = null; } mResultData = null; //不執(zhí)行的時(shí)候false mIsRunning = false; } //這個(gè)就是給是否正在錄屏提供一個(gè)get方法 public boolean ismIsRunning() { return mIsRunning; } //這個(gè)就是設(shè)置數(shù)據(jù)的方法在ActivityForResult中設(shè)置數(shù)據(jù),說(shuō)明是允許錄屏的 @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void setResultData(int resultCode, Intent resultData) { mResultCode = resultCode; mResultData = resultData; //拿到這個(gè)管理,看不懂跟上面注釋結(jié)合看 mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); //getMediaProjection(code,data)不知道這樣寫(xiě)看不看的董 //說(shuō)白了MediaProjectionManager是申請(qǐng)權(quán)限 MediaProjection是獲取申請(qǐng)結(jié)果,防止別人調(diào)取隱私 //再通過(guò)上面的setResultData方法獲取到ActivityForResult中的code,data if (mProjectionManager != null) { mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData); } } //開(kāi)始錄制了 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public boolean startRecord() { //代碼執(zhí)行順序(false,目前沒(méi)錄屏) if (mIsRunning) { return false; } //再次創(chuàng)建,防止異常 if (mMediaProjection == null) { mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData); } //關(guān)于文件路徑還有錄屏的一些參數(shù)問(wèn)題 setUpMediaRecorder(); //關(guān)于獲取錄制屏幕的大小,像素,等等一些數(shù)據(jù) createVirtualDisplay(); //開(kāi)始錄制 mMediaRecorder.start(); //稍后貼類(lèi) 監(jiān)聽(tīng)錄制情況 TalScreenUtils.startRecord(); //最多錄制三分鐘 mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN, 1000); //錄制時(shí)為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 默認(rèn)值為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; //停止時(shí)移出這條消息what mHandler.removeMessages(MSG_TYPE_COUNT_DOWN); //停止的監(jiān)聽(tīng) tip 是處理一些突發(fā)情況 比如內(nèi)存不足 TalScreenUtils.stopRecord(tip); Log.i(TAG, 'stopRecord: ' + mRecordFilePath); //錄制時(shí)間不到兩秒就刪除錄制文件 if (mRecordSeconds <= 2) { TalFileUtils.deleteSDFile(mRecordFilePath); } else { //錄制的視頻庫(kù),將數(shù)據(jù)添加到媒體庫(kù) //這個(gè)算是應(yīng)用程序之間共享數(shù)據(jù),把自己應(yīng)用的數(shù)據(jù)添加到手機(jī)的媒體庫(kù)ContentResolver //舉個(gè)例子,代碼添加手機(jī)聯(lián)系人到自己的聯(lián)系人列表,或者代碼添加圖片到自己的圖庫(kù),還有不懂得,貼個(gè)鏈接 //https://blog.csdn.net/bzlj2912009596/article/details/80248272 TalFileUtils.fileScanVideo(this, mRecordFilePath, 1280, 720, mRecordSeconds); }// mRecordFilePath = null; mRecordSeconds = 0; return true; } //下面是關(guān)于處理在一些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(); } } } //這個(gè)就是剛才講過(guò)的 繪制窗口大小,dpi問(wèn)題 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); } //這個(gè)主要是路徑,還有設(shè)置一些錄制視頻參數(shù)問(wèn)題separator 為字節(jié),占位用 @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(); } //設(shè)置音頻源 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //設(shè)置視頻源mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); //設(shè)置輸出的編碼格式 mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); if (mRecordFilePath != null) { mMediaRecorder.setOutputFile(mRecordFilePath); } else if (mRecordFilePath == null) { mMediaRecorder.setOutputFile(mRecordFilePath); } //設(shè)置錄屏?xí)r屏幕大小,這個(gè)可跟mVirtualDisplay 一起控制屏幕大小 //mVirtualDisplay 是將屏幕設(shè)置成多大多小,setVideoSize是輸出文件時(shí)屏幕多大多小 mMediaRecorder.setVideoSize(1280, 720); //圖像編碼 H264較好還有其他選擇 mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //音頻編碼mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //設(shè)置碼率 高清的話的要數(shù)越大 mMediaRecorder.setVideoEncodingBitRate((int) (1280 * 720 * 2.6)); //設(shè)置幀率,該幀率必須是硬件支持的,可以通過(guò)Camera.CameraParameter.getSupportedPreviewFpsRange()方法獲取相機(jī)支持的幀率 mMediaRecorder.setVideoFrameRate(20); try { //準(zhǔn)備 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下絕對(duì)路徑,先判斷sd卡是否掛載 public String getSaveDirectory() { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return Environment.getExternalStorageDirectory().getAbsolutePath(); } else { return null; } } //這是實(shí)現(xiàn)了Handle.CallBack中重寫(xiě)方法 handleMessage @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_TYPE_COUNT_DOWN: {String str = null;//這是內(nèi)存boolean enough = TalFileUtils.getSDFreeMemory() / (1024 * 1024) < 4;if (enough) { //空間不足,停止錄屏 str = '空間不足'; //停止錄屏?xí)r 通過(guò)接口回調(diào)一個(gè)信息,是因?yàn)槭裁赐V逛浧恋? 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 = '錄制已到限定時(shí)長(zhǎng)'; stopRecord(str); mRecordSeconds = 0;}break; } } return true; } public class RecordBinder extends Binder { public TalScreenRecordService getRecordService() { return TalScreenRecordService.this; } }}

下面貼關(guān)于手機(jī)像素還有dpi的類(lèi)

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; }

下面貼關(guān)于刪除文件,添加到媒體庫(kù)的類(lèi) 這里就使用到了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; } /** * 添加到媒體數(shù)據(jù)庫(kù) * * @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); // 標(biāo)題; values.put(MediaStore.Video.Media.DURATION, videoTime * 1000); // 時(shí)長(zhǎng) 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); // 插入時(shí)間; values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);// 文件名; values.put(MediaStore.Video.Media.DATE_MODIFIED, dateTaken / 1000);// 修改時(shí)間; values.put(MediaStore.Video.Media.DATE_ADDED, dateTaken / 1000); // 添加時(shí)間; 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上每一個(gè)block的SIZElong nBlockSize = statfs.getBlockSize();// 獲取可供程序使用的Block的數(shù)量// long nAvailBlock = statfs.getAvailableBlocksLong();long nAvailBlock = statfs.getAvailableBlocks();// 計(jì)算SDCard剩余大小Bytelong 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);// 單位Bytereturn info.availMem / 1024 / 1024; } } return 0; }}

還有一個(gè)類(lèi) 是為整個(gè)Service提供了便捷訪問(wèn)的類(lèi) ,將一些監(jiān)聽(tīng)service中的變化放到集合里來(lái)做

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,錄制結(jié)束的提示語(yǔ)正在顯示 public static boolean s_IsRecordingTipShowing = false; /** * 錄屏功能 5.0+ 的手機(jī)才能使用 * @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(); } } /** * 開(kāi)始錄制 */ 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){ //存在錄屏授權(quán)的Activity activity.startActivityForResult(intent,requestCode); }else { Toast.makeText(activity, '不能錄音', Toast.LENGTH_SHORT).show(); } }} else { s_ScreenRecordService.startRecord();} } } } /** * 獲取用戶(hù)允許錄屏后,設(shè)置必要的數(shù)據(jù) * @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; } /** * 判斷當(dāng)前是否在錄制 * @return */ public static boolean isCurrentRecording(){ if (isScreenRecordEnable() && s_ScreenRecordService!= null) { return s_ScreenRecordService.ismIsRunning(); } return false; } /** * true,錄制結(jié)束的提示語(yǔ)正在顯示 * @return */ public static boolean isRecodingTipShow(){ return s_IsRecordingTipShowing; } public static void setRecordingStatus(boolean isShow){ s_IsRecordingTipShowing = isShow; } /** * 系統(tǒng)正在錄屏,app 錄屏?xí)袥_突,清理掉一些數(shù)據(jù) */ 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(); }}

到了最后了,是一些調(diào)用時(shí)的內(nèi)容

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需要?jiǎng)?chuàng)建連接 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //啟動(dòng)service TalScreenRecordService.RecordBinder recordBinder = (TalScreenRecordService.RecordBinder) service; TalScreenRecordService recordService = recordBinder.getRecordService(); //這個(gè)其實(shí)是傳值在使用的activity中拿到Service TalScreenUtils.setScreenService(recordService); } @Override public void onServiceDisconnected(ComponentName name) { } }; //開(kāi)啟service,意圖跳轉(zhuǎn)到service,別忘了AndroidManifest里面需要注冊(cè)這個(gè)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(); //兩個(gè)按鈕 一個(gè)開(kāi)始 一個(gè)結(jié)束 xml不貼了 mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {if (TalFileUtils.getFreeMem(MainActivity.this) < 100) { Toast.makeText(MainActivity.this, '手機(jī)內(nèi)存不足,請(qǐng)清理后再進(jìn)行錄屏', Toast.LENGTH_SHORT).show(); return;}//開(kāi)始錄屏錄音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() { //權(quán)限申請(qǐng) TalAllow.requestPermissions(this, REQUEST_ALLOW); //獲取屏幕大小 在onCreate里面初始化就可以獲取 TalScreenParams.init(this); startService(); } @Override protected void onStop() { super.onStop(); //在對(duì)用戶(hù)可見(jiàn)不可交互的時(shí)候防止異常 TalScreenUtils.clear(); } //打印權(quán)限獲取情況日志 @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); } //在用戶(hù)允許錄屏后拿到確定的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 { //設(shè)置數(shù)據(jù),在用戶(hù)允許后 調(diào)用了開(kāi)始錄屏的方法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); }}

至此,一個(gè)還算比較完整的錄屏錄音功能就可以實(shí)現(xiàn),不足之處請(qǐng)批評(píng)指正

總結(jié)

到此這篇關(guān)于android MediaRecorder錄屏?xí)r帶錄音功能實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)android MediaRecorder錄屏帶錄音內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Android
相關(guān)文章:
主站蜘蛛池模板: 加中寰球移民官网-美国移民公司,移民机构,移民中介,移民咨询,投资移民 | 山东锐智科电检测仪器有限公司_超声波测厚仪,涂层测厚仪,里氏硬度计,电火花检漏仪,地下管线探测仪 | NM-02立式吸污机_ZHCS-02软轴刷_二合一吸刷软轴刷-厦门地坤科技有限公司 | 工控机,嵌入式主板,工业主板,arm主板,图像采集卡,poe网卡,朗锐智科 | 膜结构车棚|上海膜结构车棚|上海车棚厂家|上海膜结构公司 | 玻璃瓶厂家_酱菜瓶厂家_饮料瓶厂家_酒瓶厂家_玻璃杯厂家_徐州东明玻璃制品有限公司 | 三效蒸发器_多效蒸发器价格_四效三效蒸发器厂家-青岛康景辉 | 证券新闻,热播美式保罗1984第二部_腾讯1080p-仁爱影院 | 泵阀展|阀门展|水泵展|流体机械展 -2025上海国际泵管阀展览会flowtech china | 液压油缸-液压站生产厂家-洛阳泰诺液压科技有限公司 | 青岛球场围网,青岛车间隔离网,青岛机器人围栏,青岛水源地围网,青岛围网,青岛隔离栅-青岛晟腾金属制品有限公司 | 光伏家 - 太阳能光伏发电_分布式光伏发电_太阳能光伏网 | 旗杆生产厂家_不锈钢锥形旗杆价格_铝合金电动旗杆-上海锥升金属科技有限公司 | 建大仁科-温湿度变送器|温湿度传感器|温湿度记录仪_厂家_价格-山东仁科 | 仿古建筑设计-仿古建筑施工-仿古建筑公司-汉匠古建筑设计院 | 质构仪_鱼糜弹性仪-上海腾拔仪器科技有限公司 | 电伴热系统施工_仪表电伴热保温箱厂家_沃安电伴热管缆工业技术(济南)有限公司 | pbt头梳丝_牙刷丝_尼龙毛刷丝_PP塑料纤维合成毛丝定制厂_广州明旺 | 冰晶石|碱性嫩黄闪蒸干燥机-有机垃圾烘干设备-草酸钙盘式干燥机-常州市宝康干燥 | 可程式恒温恒湿试验箱|恒温恒湿箱|恒温恒湿试验箱|恒温恒湿老化试验箱|高低温试验箱价格报价-广东德瑞检测设备有限公司 | 仓储笼_金属箱租赁_循环包装_铁网箱_蝴蝶笼租赁_酷龙仓储笼租赁 测试治具|过炉治具|过锡炉治具|工装夹具|测试夹具|允睿自动化设备 | 工作心得_读书心得_学习心得_找心得体会范文就上学道文库 | 达利园物流科技集团-| 铝镁锰板_铝镁锰合金板_铝镁锰板厂家_铝镁锰金属屋面板_安徽建科 | 金现代信息产业股份有限公司--数字化解决方案供应商 | 青岛侦探_青岛侦探事务所_青岛劝退小三_青岛调查出轨取证公司_青岛婚外情取证-青岛探真调查事务所 | 南京种植牙医院【官方挂号】_南京治疗种植牙医院那个好_南京看种植牙哪里好_南京茀莱堡口腔医院 尼龙PA610树脂,尼龙PA612树脂,尼龙PA1010树脂,透明尼龙-谷骐科技【官网】 | 好看的韩国漫画_韩漫在线免费阅读-汗汗漫画 | 专业深孔加工_东莞深孔钻加工_东莞深孔钻_东莞深孔加工_模具深孔钻加工厂-东莞市超耀实业有限公司 | 东莞注册公司-代办营业执照-东莞公司注册代理记账-极刻财税 | 煤机配件厂家_刮板机配件_链轮轴组_河南双志机械设备有限公司 | 青岛球场围网,青岛车间隔离网,青岛机器人围栏,青岛水源地围网,青岛围网,青岛隔离栅-青岛晟腾金属制品有限公司 | 自动配料系统_称重配料控制系统厂家 | 食品质构分析仪-氧化诱导分析仪-瞬态法导热系数仪|热冰百科 | 月嫂_保姆_育婴_催乳_母婴护理_产后康复_养老护理-吉祥到家家政 硫酸亚铁-聚合硫酸铁-除氟除磷剂-复合碳源-污水处理药剂厂家—长隆科技 | 广州中央空调回收,二手中央空调回收,旧空调回收,制冷设备回收,冷气机组回收公司-广州益夫制冷设备回收公司 | 精密钢管,冷拔精密无缝钢管,精密钢管厂,精密钢管制造厂家,精密钢管生产厂家,山东精密钢管厂家 | 手持式线材张力计-套帽式风量罩-深圳市欧亚精密仪器有限公司 | 河南凯邦机械制造有限公司| RTO换向阀_VOC高温阀门_加热炉切断阀_双偏心软密封蝶阀_煤气蝶阀_提升阀-湖北霍科德阀门有限公司 | 动库网动库商城-体育用品专卖店:羽毛球,乒乓球拍,网球,户外装备,运动鞋,运动包,运动服饰专卖店-正品运动品网上商城动库商城网 - 动库商城 |