Android 在 service 中实现后台录像
阅读原文时间:2021年04月20日阅读:1

在开篇之前,如不了解 MediaRecorder,可以先行阅读 Android–MediaRecorder录音录像

另外,在 stackoverflow 上也有关于 service 录像的回答:Background video recording in Android 4.0。我所实现的功能也参考了此 answer。

此外,关于 WindowsManager 的先验知识还可以参考这篇博客:Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果

进入正题。

1、定义录像布局:recorder_layout.xml

<RelativeLayout
    android:id="@+id/root"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:keepScreenOn="true"
    >

    <SurfaceView
            android:id="@+id/sv_recorder"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clickable="true"
            />
</RelativeLayout>

2、实现 MonitorService.java

public class MonitorService extends Service implements SurfaceHolder.Callback {
    public static final String ACTION_BACK_HOME = "com.byd.recorder.ACTION_BACK_HOME";
    public static final String ACTION_SHOW_RECORDER = "com.byd.recorder.ACTION_SHOW_RECORDER";

    private static final int NOTIFICATION_DI = 1234;

    private WindowManager mWindowManager;
    private WindowManager.LayoutParams mLayoutParams;
    private int screenWidth;
    private int screenHeight;
    private View mRecorderView;
    private SurfaceView mSurfaceView;

    /* RecorderManager manages the job of video recording */
    private RecorderManager mRecorderManager;
    private LocalBroadcastManager mLocalBroadcastManager;
    private LocalReceiver mLocalReceiver;

    @Override
    public void onCreate() {
        super.onCreate();

        // Start foreground service to avoid unexpected kill
        Notification notification = new Notification.Builder(this)
                .setContentTitle("Background Video Recorder")
                .setContentText("Click into the application")
                .setSmallIcon(R.drawable.icon)
                .setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0))
                .build();
        startForeground(NOTIFICATION_DI, notification);

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mRecorderView = LayoutInflater.from(this).inflate(R.layout.recorder_layout, null);
        mSurfaceView = (SurfaceView) mRecorderView.findViewById(R.id.sv_recorder);
        mSurfaceView.getHolder().addCallback(this);

        DisplayMetrics dm = getResources().getDisplayMetrics();
        screenWidth = dm.widthPixels;
        screenHeight = dm.heightPixels;
        mLayoutParams = new WindowManager.LayoutParams();
        mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        mLayoutParams.width = screenWidth;
        mLayoutParams.height = screenHeight;
        mWindowManager.addView(mRecorderView, mLayoutParams);

        registerLocalReceiver();
    }

    @Override
    public void onDestroy() {
        if (mWindowManager != null) {
            mWindowManager.removeView(mRecorderView);
        }
        if (mRecorderManager != null) {
            mRecorderManager.stop();
        }

        mLocalBroadcastManager.unregisterReceiver(mLocalReceiver);
        stopForeground(true);
    }

    private void registerLocalReceiver() {
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_BACK_HOME);
        intentFilter.addAction(ACTION_SHOW_RECORDER);
        mLocalReceiver = new LocalReceiver();
        mLocalBroadcastManager.registerReceiver(mLocalReceiver, intentFilter);
    }

    public void hideRecorder(boolean isHide) {
        if (isHide) {
            mLayoutParams.width = 1;
            mLayoutParams.height = 1;
        } else {
            mLayoutParams.width = screenWidth;
            mLayoutParams.height = screenHeight;
        }
        mWindowManager.updateViewLayout(mRecorderView, mLayoutParams);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        mRecorderManager = new RecorderManager();
        mRecorderManager.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }

    private class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_BACK_HOME)) {
                hideRecorder(true);
            }
            if (intent.getAction().equals(ACTION_SHOW_RECORDER)) {
                hideRecorder(false);
            }
        }
    }
}

3、几点说明

  • mLayoutParams.widthmLayoutParams.height 决定了 mRecorderView 所显示出来的大小,所以我们可以通过 WindowManager.updateViewLayout(view, layoutParams) 这一方法实现隐藏和显示监控录像。

  • 我们在进入 MainActivity 后,可以向 MonitorService 发送本地广播,实现对监控录像的显示和隐藏

    private void hideRecorder() {
        Intent intent = new Intent(MonitorService.ACTION_BACK_HOME);
        mLocalBroadcastManager.sendBroadcast(intent);
    }
    
    private void showRecorder() {
        Intent intent = new Intent(MonitorService.ACTION_SHOW_RECORDER);
        mLocalBroadcastManager.sendBroadcast(intent);
    }

4、没有 demo project,请根据以上关键源码实现你想要的功能吧!

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章