为什么MediaRecorder功能不会导致ANR错误?

7
我使用 Android 5.1 中的 MediaRecorder 和 MediaProjection 函数开始了一个录屏服务,我认为代码 Method 1 会在主线程中运行,从而导致“应用无响应”错误。
  1. 我测试了长时间运行代码 Method 1,没有出现“应用无响应”错误,为什么?这是否意味着函数 MediaRecorder 和 MediaProjection 在不同的线程中工作?

  2. 在代码 Method 2 中,我创建了一个线程来运行 mRecordHelper.StartRecord(mRecordArg,resultCode,mIntent); 但是我收到了错误信息 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(), ,为什么?

感谢您的帮助。

调用代码:

MPublicPar.RecordArg mRecordArg =new MPublicPar().new RecordArg(mContext);
Intent intent = new Intent(mContext,bll.RecordService.class);
intent.putExtra("resultCode",resultCode);
intent.putExtra("dataIntent",data);
intent.putExtra("mRecordArg",mRecordArg);

startService(intent);

方法一

public class RecordService extends Service { 

    private RecordHelper mRecordHelper;
    private Context mContext;

    @Override
    public void onCreate(){  
        mContext=this;

        mRecordHelper=new RecordHelper(mContext);
    }

    @Override
    public void onDestroy(){
        mRecordHelper.StopRecord();
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

       final int resultCode=intent.getIntExtra("resultCode",0);
       final Intent mIntent=(Intent)intent.getParcelableExtra("dataIntent");
       final MPublicPar.RecordArg mRecordArg=(MPublicPar.RecordArg)intent.getSerializableExtra("mRecordArg");

        mRecordHelper.StartRecord(mRecordArg,resultCode,mIntent);
        return super.onStartCommand(intent, flags, startId);
    }

}

方法2

public class RecordService extends Service { 

    private RecordHelper mRecordHelper;
    private Context mContext;

    @Override
    public void onCreate(){  
        mContext=this;

        mRecordHelper=new RecordHelper(mContext);
    }

    @Override
    public void onDestroy(){
        mRecordHelper.StopRecord();
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

       final int resultCode=intent.getIntExtra("resultCode",0);
       final Intent mIntent=(Intent)intent.getParcelableExtra("dataIntent");
       final MPublicPar.RecordArg mRecordArg=(MPublicPar.RecordArg)intent.getSerializableExtra("mRecordArg");    

       new Thread(new Runnable() {
            public void run() {    
                mRecordHelper.StartRecord(mRecordArg,resultCode,mIntent);           
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

}

RecordHelper.cs

public class RecordHelper {

    private  MediaRecorder mMediaRecorder;
    private  MediaProjection mMediaProjection;
    private  VirtualDisplay mVirtualDisplay;
    private  MediaProjectionManager mProjectionManager;

    private Context mContext;
    private Toast mToastText;

    public RecordHelper(Context mContext){
        this.mContext=mContext;
        mProjectionManager = (MediaProjectionManager) mContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        mMediaRecorder = new MediaRecorder();
    }

    public void StartRecord(RecordArg mRecordArg, int resultCode, Intent data){

        initRecorder(mRecordArg);
        prepareRecorder();

        mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
        MediaProjectionCallback mMediaProjectionCallback = new MediaProjectionCallback();
        mMediaProjection.registerCallback(mMediaProjectionCallback, null);

        mVirtualDisplay=createVirtualDisplay(mRecordArg);

        DelayStartRecord(mRecordArg);
    }


    public void StopRecord(){
        try {
            mMediaRecorder.stop();
            mMediaRecorder.reset();

            mVirtualDisplay.release();
            mMediaRecorder.release();

            mMediaProjection.stop();
            mMediaProjection = null;

        }catch (Exception e){
            Utility.LogError("StopRecord Error " + e.getMessage() + "  " + e.toString());
        }
    }

    private void DelayStartRecord(RecordArg mRecordArg){
        mMediaRecorder.start();
    }


    private void initRecorder(RecordArg mRecordArg) {
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
        mMediaRecorder.setVideoFrameRate(30);
        mMediaRecorder.setVideoSize(mRecordArg.screenWidth, mRecordArg.screenHeight);
        mMediaRecorder.setOutputFile(mRecordArg.videoFilename);
    }


    private void prepareRecorder() {
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            e.printStackTrace();
            Utility.LogError(e.getMessage());

        } catch (IOException e) {
            e.printStackTrace();
            Utility.LogError(e.getMessage());
        }
    }


    private VirtualDisplay createVirtualDisplay(RecordArg mRecordArg) {
          return mMediaProjection.createVirtualDisplay("ScreenRecord",
                 mRecordArg.screenWidth, mRecordArg.screenHeight, mRecordArg.mScreenDensity,
                 DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                 mMediaRecorder.getSurface(), null /*Callbacks*/, null /*Handler*/);
    }


    //Called when the MediaProjection session is no longer valid.
    private  class MediaProjectionCallback extends MediaProjection.Callback {
        @Override
        public void onStop() {

        }
    }

}

在第二种方法中,我认为你应该将它放在UI线程上。 - tiny sunlight
1个回答

4
但是我得到了java.lang.RuntimeException错误:无法在未调用Looper.prepare()的线程内创建处理程序,为什么?
我猜你已经明白了,因此才会问第二个问题。事实上,如果您在主线程上调用mRecordHelper.StartRecord(mRecordArg,resultCode,mIntent)并不意味着所有代码函数都在该线程上运行,它只是在调用线程(即主线程)上更新UI信息,并在后台线程上执行艰苦的工作。如果您明确地从不同的线程调用,则指示它从该线程更改UI对象,因此会出现异常-想象一下使用异步任务或SurfaceView的类,不要混淆,您可以随时检查源代码并了解其工作原理。
这不是什么大问题-(我谦卑地说)
为什么?这是否意味着MediaRecorder和MediaProjection函数在单独的线程中工作?
请参考上面的内容,我猜是。

谢谢!有没有办公文档告诉我MediaRecorder和MediaProjection在单独的线程中工作? - HelloCW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接