1. 程式人生 > 程式設計 >android MediaRecorder實現錄屏時帶錄音功能

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",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錄屏帶錄音內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!