前言
昨天是个很令人难受的日子,阳历公元2020年4月4日 清明节 我们虽然战胜了病魔,但是在这个漫长的过程中,每天对于前线来说都是煎熬的日子 医生加油!China 加油!
愿逝者安息,愿生者奋发,愿祖国昌盛。

感慨完了,下面说说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;
    //这个就是我们要获取录制屏幕的大小,像素,等等一些数据
    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对象
	//关于返回值问题
  @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
        //举个例子,代码添加手机联系人到自己的联系人列表,或者代码添加图片到自己的图库,
            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", 1280, 720, 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);
    }
}

至此,一个还算比较完整的录屏录音功能就可以实现,不足之处请批评指正