Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the MediaRecorder function cause ANR error?

Tags:

android

I start a service to reord screen using MediaRecorder and MediaProjection function in Android 5.1 , I think the code Method 1 will cause Application Not Responding error because it works in main thread.

  1. I test the code Method 1 to recode screen long time, it doesn't occur "Application Not Responding error", why? Does it mean that the function MediaRecorder and MediaProjection worked in separated thread?

  2. In the code Method 2, I create a thread to run mRecordHelper.StartRecord(mRecordArg,resultCode,mIntent); but I get the error java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(), why?

Thanks for your help.

Call Code

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

Method 1

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

}

Method 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() {

        }
    }

}
like image 745
HelloCW Avatar asked Nov 05 '15 09:11

HelloCW


1 Answers

but I get the error java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(), why?

i guess you know hence your second question. The fact that if you call mRecordHelper.StartRecord(mRecordArg,resultCode,mIntent); on the Main thread, does not mean all code functions runs on that thread, all it does is it updates the UI informations on the calling Thread-which is the main thread, and the hard work on a background Thread. if you xplicitly call from a different thread you are instructing it to change a UI object from that thread hence you get that exception- picture a class using async task, or SurfaceView, do not get confused sir, you can always go check the source code and see how it works.

This is not a big deal -(i humbly speak)

why? Does it mean that the function MediaRecorder and MediaProjection worked in separated thread?

check the above -i guess yes

like image 111
Elltz Avatar answered Oct 14 '22 07:10

Elltz