9

I want to write an APP to record screen, there are two way, RecordHelper_Method_A and RecordHelper_Method_B .

In RecordHelper_Method_A, I define mMediaRecorder, MediaProjection mMediaProjection and mVirtualDisplay as static var, it's easy to invoke, such as StartRecord( mContext, requestCode, resultCode,data), StopRecord().

and in RecordHelper_Method_B, I need to define mMediaRecorder, MediaProjection mMediaProjection in main Activity class, and pass the parameters when I invoke StartRecord(mMediaRecorder, mMediaProjection,mVirtualDisplay), 'StopRecord(mMediaRecorder,mMediaProjection,mVirtualDisplay)`..., it's a little complex.

I don't know which one is the better, and more I don't know if these static var can be released correctly in RecordHelper_Method_A when I end the APP.

BTW, if you have the better way, would you please tell me ? Thanks!

RecordHelper_Method_A

public class RecordHelper_Method_A {

    private static MediaRecorder mMediaRecorder;
    private static MediaProjection mMediaProjection;
    private static VirtualDisplay mVirtualDisplay;

    public static void StartRecord(Context mContext,int requestCode, int resultCode, Intent data){

        mMediaRecorder = new MediaRecorder();
        initRecorder();

        MediaProjectionManager mProjectionManager = (MediaProjectionManager) mContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);

        mVirtualDisplay=mMediaProjection.createVirtualDisplay("MainActivity",
                400,600, 300,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mMediaRecorder.getSurface(), null, null);

        MediaProjectionCallback mMediaProjectionCallback = new MediaProjectionCallback();
        mMediaProjection.registerCallback(mMediaProjectionCallback, null);

        mMediaRecorder.start();
    }

    public static void StopRecord(){
        mMediaProjection=null;
        mMediaRecorder.stop();
        mMediaRecorder.reset();
        mMediaRecorder.release();
        mVirtualDisplay.release();
    }


    private static void initRecorder() {
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        //...
    }

    private static class MediaProjectionCallback extends MediaProjection.Callback {
        @Override
        public void onStop() {
            mMediaRecorder.stop();
        }
    }
}

RecordHelper_Method_B

public class RecordHelper_Method_B {

    public static void StartRecord(MediaRecorder mMediaRecorder,MediaProjection mMediaProjection,VirtualDisplay mVirtualDisplay){

        initRecorder(mMediaRecorder);

        mVirtualDisplay=mMediaProjection.createVirtualDisplay("MainActivity",
                400,600, 300,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mMediaRecorder.getSurface(), null, null);

        MediaProjectionCallback mMediaProjectionCallback = new MediaProjectionCallback(mMediaRecorder);
        mMediaProjection.registerCallback(mMediaProjectionCallback, null);

        mMediaRecorder.start();
    }

    public static void StopRecord(MediaRecorder mMediaRecorder,MediaProjection mMediaProjection,VirtualDisplay mVirtualDisplay){
        mMediaProjection=null;
        mMediaRecorder.stop();
        mMediaRecorder.reset();
        mMediaRecorder.release();
        mVirtualDisplay.release();
    }


    private static void initRecorder(MediaRecorder mMediaRecorder) {
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        //...
    }

    private static class MediaProjectionCallback extends MediaProjection.Callback {
        MediaRecorder mMediaRecorder;
        public MediaProjectionCallback(MediaRecorder mMediaRecorder){
            this.mMediaRecorder=mMediaRecorder;
        }

        @Override
        public void onStop() {
            mMediaRecorder.stop();
        }
    }

}
Henry
  • 17,490
  • 7
  • 63
  • 98
HelloCW
  • 843
  • 22
  • 125
  • 310
  • *I don't know if these static var can be released correctly in RecordHelper_Method_A when I end the APP.* - static variables are automatically "released" when the object that houses them is destroyed or unloaded. One scenario where this happens is when the app is closed, yes – Tim Oct 22 '15 at 09:30
  • Thanks! Normally, static var can be released automatically, but sometimes the app maybe crash without invoking StopRecord(), and sometimes StartRecord(...) is invoked repeatedly, will all scenarios guarantee these static var released correctly? – HelloCW Oct 22 '15 at 14:19
  • @HelloCW. It depends on where you call this methods. Static vars will be released with application process. But in Android application process lifecycle is not equal to its components lifecycle. You should not use static variables that hold resources. – Vladimir Petrakovich Oct 24 '15 at 12:37

5 Answers5

9

I would suggest Objects not living statically. Whatever object or resource that you create, should die when the activity dies. So creating these resources in the activity and then passing it is good.

Also, I see that in both of the methods that you suggested, the methods are themselves static. It's better to create an object for the class and then pass the resources to this object. This would prevent accidental memory leaks. You could do something like this in your Activity.

RecordHelper_Method_B helper = new RecordHelper_Method_B ();
helper.StopRecord(mMediaRecorder,mMediaProjection,mVirtualDisplay);

This keeps things simple. Once your Activity dies, so will the helper object. So all resources will be released for sure.

Henry
  • 17,490
  • 7
  • 63
  • 98
  • Thanks! I think "Objects not living statically" is the better way too, but it's a little complex to invoke function because I need pass many parameters every time. – HelloCW Oct 26 '15 at 00:29
  • Then use a constructor or a Builder pattern, so that when you create the object you also have a reference to all other objects passed. That way you need not pass stuff in every method, but only have to do it once. – Henry Oct 26 '15 at 03:25
3

In general, if you want to use static functions, you should prefer to not define static variables from outside. It will result in a degradation of the performances. Also, a static method should be sufficent by "itself" for lisibility and maintenance.

As we are in Android context, you can read this article for further details/tips : http://developer.android.com/training/articles/perf-tips.html

llfbandit
  • 168
  • 6
1

Dependency Injection is better all the time (you see the name classic). so let go of the static variables and look for a way to feed your methods etc etc.

using this means more re-usability of your code, more readability, less lifespan of objects-as they die when method is done etc etc.

Elltz
  • 10,730
  • 4
  • 31
  • 59
1

If static variables are suggested not be used then why were they introduced. Hi guys, I guess it's all about to learn by experience that how to use static variables and handle them in effective way. I only want to say that just don't take it as using static can be harmful rather using them without knowing is harmful. :)

1

Static variables are ok when they don't contains mutable state (ie constants or readonly values). Otherwise they are global variables and as such their usage is considered as a bad practice. Why?
From Wikipedia or the Evil Static Variables :

  • Decrease testability.
  • Increases complexity (depends on encapsulation)
  • Name sharing (more or less true, depends on languages)

Even static behaviour could be problematic if it refers to unique resources and then not share-able and testable (database, file system, sockets, etc...)

Community
  • 1
  • 1
Fab
  • 14,327
  • 5
  • 49
  • 68