android MediaRecorder實現(xiàn)錄屏?xí)r帶錄音功能
下面說說android的事把
最近是不是也會遇到需求中需要用到錄屏錄音的功能,最近也是遇到的 現(xiàn)在整理完記錄一下
首先呢,錄音錄屏需要權(quán)限 先貼一個動態(tài)權(quán)限類
public class TalAllow {
/**
* RECORD_AUDIO 音頻權(quán)限
* WRITE_EXTERNAL_STORAGE 寫入權(quán)限
* CAMERA 相機權(quán)限
*/
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);
}
}
}
有需求需要判斷權(quán)限的呢 插入個鏈接 (上面那個類code碼為100)
判斷是否有權(quán)限
下面重點來了
首先說明一下這個錄屏和錄音是在服務(wù)里面做的,所以呢貼一個服務(wù)類
這個代碼絕對有質(zhì)量 做了很多處理,下面一行一行解讀把
//首先呢實現(xiàn)的是Handle.Callback接口 主要是做時間及計時時間回調(diào)的,會重新寫HandleMessage方法,其實我個覺得跟在括號{} 里面重寫沒啥區(qū)別就是簡潔頁面
public class TalScreenRecordService extends Service implements Handler.Callback {
//這個就不解釋了吧 log
private static final String TAG = "TalScreenRecordService";
//這個類是管理類拿到服務(wù)后會通過下面的類申請錄屏,點擊允許,
//其中會回調(diào)兩個參數(shù),code碼 和 data,都在ActivityForResult中進行判斷code
private MediaProjectionManager mProjectionManager;
//這個會拿到申請的結(jié)果
private MediaProjection mMediaProjection;
//這個類就是我們主要的錄屏錄音的類啦
private MediaRecorder mMediaRecorder;
//這個就是我們要獲取錄制屏幕的大小,像素,等等一些數(shù)據(jù)
//關(guān)于這類更詳細的介紹https://blog.csdn.net/qq_16628781/article/details/62038163
private VirtualDisplay mVirtualDisplay;
//是否正在錄制 false 沒有錄制
private boolean mIsRunning;
//獲取屏幕的寬高和像素密度 稍后貼類
private int mRecordWidth = TalScreenParams.getScreenWidth();
private int mRecordHeight = TalScreenParams.getScreenWidth();
private int mScreenDpi = TalScreenParams.getScreenDpi();
//code data 就是上面說的允許后回調(diào)
private int mResultCode;
private Intent mResultData;
//錄屏文件的保存地址
private String mRecordFilePath;
private Handler mHandler;
//已經(jīng)錄制多少秒了
private int mRecordSeconds = 0;
//handle發(fā)送消息時的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對象
//關(guān)于返回值問題https://blog.csdn.net/github_37663523/article/details/78811539
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
//沒有錄制
mIsRunning = false;
//創(chuàng)建對象 在create方法里只執(zhí)行一次
mMediaRecorder = new MediaRecorder();
// 由于實現(xiàn)了CallBack接口,在這里注冊一下接口(個人覺得高大的寫法,簡潔)
mHandler = new Handler(Looper.getMainLooper(), this);
}
@Override
public void onDestroy() {
super.onDestroy();
}
//數(shù)據(jù)不為空
public boolean isReady() {
return mMediaProjection != null && mResultData != null;
}
//清除的方法 避免內(nèi)存泄漏 相信都看得懂
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void clearRecordElement() {
clearAll();
if (mMediaRecorder != null) {
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
}
mResultData = null;
//不執(zhí)行的時候false
mIsRunning = false;
}
//這個就是給是否正在錄屏提供一個get方法
public boolean ismIsRunning() {
return mIsRunning;
}
//這個就是設(shè)置數(shù)據(jù)的方法在ActivityForResult中設(shè)置數(shù)據(jù),說明是允許錄屏的
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setResultData(int resultCode, Intent resultData) {
mResultCode = resultCode;
mResultData = resultData;
//拿到這個管理,看不懂跟上面注釋結(jié)合看
mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
//getMediaProjection(code,data)不知道這樣寫看不看的董
//說白了MediaProjectionManager是申請權(quán)限 MediaProjection是獲取申請結(jié)果,防止別人調(diào)取隱私
//再通過上面的setResultData方法獲取到ActivityForResult中的code,data
if (mProjectionManager != null) {
mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData);
}
}
//開始錄制了
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public boolean startRecord() {
//代碼執(zhí)行順序(false,目前沒錄屏)
if (mIsRunning) {
return false;
}
//再次創(chuàng)建,防止異常
if (mMediaProjection == null) {
mMediaProjection = mProjectionManager.getMediaProjection(mResultCode, mResultData);
}
//關(guān)于文件路徑還有錄屏的一些參數(shù)問題
setUpMediaRecorder();
//關(guān)于獲取錄制屏幕的大小,像素,等等一些數(shù)據(jù)
createVirtualDisplay();
//開始錄制
mMediaRecorder.start();
//稍后貼類 監(jiān)聽錄制情況
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);
//停止的監(jiān)聽 tip 是處理一些突發(fā)情況 比如內(nèi)存不足
TalScreenUtils.stopRecord(tip);
Log.i(TAG, "stopRecord: " + mRecordFilePath);
//錄制時間不到兩秒就刪除錄制文件
if (mRecordSeconds <= 2) {
TalFileUtils.deleteSDFile(mRecordFilePath);
} else {
//錄制的視頻庫,將數(shù)據(jù)添加到媒體庫
//這個算是應(yīng)用程序之間共享數(shù)據(jù),把自己應(yīng)用的數(shù)據(jù)添加到手機的媒體庫ContentResolver
//舉個例子,代碼添加手機聯(lián)系人到自己的聯(lián)系人列表,或者代碼添加圖片到自己的圖庫,還有不懂得,貼個鏈接
//https://blog.csdn.net/bzlj2912009596/article/details/80248272
TalFileUtils.fileScanVideo(this, mRecordFilePath, 1280, 720, mRecordSeconds);
}
// mRecordFilePath = null;
mRecordSeconds = 0;
return true;
}
//下面是關(guān)于處理在一些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);
}
//這個主要是路徑,還有設(shè)置一些錄制視頻參數(shù)問題separator 為字節(jié),占位用
@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();
}
//設(shè)置音頻源
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//設(shè)置視頻源
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
//設(shè)置輸出的編碼格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
if (mRecordFilePath != null) {
mMediaRecorder.setOutputFile(mRecordFilePath);
} else if (mRecordFilePath == null) {
mMediaRecorder.setOutputFile(mRecordFilePath);
}
//設(shè)置錄屏?xí)r屏幕大小,這個可跟mVirtualDisplay 一起控制屏幕大小
//mVirtualDisplay 是將屏幕設(shè)置成多大多小,setVideoSize是輸出文件時屏幕多大多小
mMediaRecorder.setVideoSize(1280, 720);
//圖像編碼 H264較好還有其他選擇
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
//音頻編碼
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//設(shè)置碼率 高清的話的要數(shù)越大
mMediaRecorder.setVideoEncodingBitRate((int) (1280 * 720 * 2.6));
//設(shè)置幀率,該幀率必須是硬件支持的,可以通過Camera.CameraParameter.getSupportedPreviewFpsRange()方法獲取相機支持的幀率
mMediaRecorder.setVideoFrameRate(20);
try {
//準(zhǔn)備
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;
}
}
//這是實現(xiàn)了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;
//這是內(nèi)存
boolean enough = TalFileUtils.getSDFreeMemory() / (1024 * 1024) < 4;
if (enough) {
//空間不足,停止錄屏
str = "空間不足";
//停止錄屏?xí)r 通過接口回調(diào)一個信息,是因為什么停止錄屏的
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;
}
}
}
下面貼關(guān)于手機像素還有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;
}
下面貼關(guān)于刪除文件,添加到媒體庫的類 這里就使用到了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;
}
/**
* 添加到媒體數(shù)據(jù)庫
*
* @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); // 標(biāo)題;
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的數(shù)量
// 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提供了便捷訪問的類 ,將一些監(jiān)聽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,錄制結(jié)束的提示語正在顯示
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){
//存在錄屏授權(quán)的Activity
activity.startActivityForResult(intent,requestCode);
}else {
Toast.makeText(activity, "不能錄音", Toast.LENGTH_SHORT).show();
}
}
} else {
s_ScreenRecordService.startRecord();
}
}
}
}
/**
* 獲取用戶允許錄屏后,設(shè)置必要的數(shù)據(jù)
* @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;
}
/**
* 判斷當(dāng)前是否在錄制
* @return
*/
public static boolean isCurrentRecording(){
if (isScreenRecordEnable() && s_ScreenRecordService!= null) {
return s_ScreenRecordService.ismIsRunning();
}
return false;
}
/**
* true,錄制結(jié)束的提示語正在顯示
* @return
*/
public static boolean isRecodingTipShow(){
return s_IsRecordingTipShowing;
}
public static void setRecordingStatus(boolean isShow){
s_IsRecordingTipShowing = isShow;
}
/**
* 系統(tǒng)正在錄屏,app 錄屏?xí)袥_突,清理掉一些數(shù)據(jù)
*/
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();
}
}
到了最后了,是一些調(diào)用時的內(nèi)容
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需要創(chuàng)建連接
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,意圖跳轉(zhuǎn)到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();
//兩個按鈕 一個開始 一個結(jié)束 xml不貼了
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (TalFileUtils.getFreeMem(MainActivity.this) < 100) {
Toast.makeText(MainActivity.this, "手機內(nèi)存不足,請清理后再進行錄屏", 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() {
//權(quán)限申請
TalAllow.requestPermissions(this, REQUEST_ALLOW);
//獲取屏幕大小 在onCreate里面初始化就可以獲取
TalScreenParams.init(this);
startService();
}
@Override
protected void onStop() {
super.onStop();
//在對用戶可見不可交互的時候防止異常
TalScreenUtils.clear();
}
//打印權(quán)限獲取情況日志
@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 {
//設(shè)置數(shù)據(jù),在用戶允許后 調(diào)用了開始錄屏的方法
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);
}
}
至此,一個還算比較完整的錄屏錄音功能就可以實現(xiàn),不足之處請批評指正
總結(jié)
到此這篇關(guān)于android MediaRecorder錄屏?xí)r帶錄音功能實現(xiàn)的文章就介紹到這了,更多相關(guān)android MediaRecorder錄屏帶錄音內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android編程錄音工具類RecorderUtil定義與用法示例
- Android實現(xiàn)錄音功能實現(xiàn)實例(MediaRecorder)
- Android使用AudioRecord實現(xiàn)暫停錄音功能實例代碼
- Android錄音--AudioRecord、MediaRecorder的使用
- android 通過MediaRecorder實現(xiàn)簡單的錄音示例
- Android使用MediaRecorder實現(xiàn)錄音及播放
- Android App調(diào)用MediaRecorder實現(xiàn)錄音功能的實例
- Android音頻錄制MediaRecorder之簡易的錄音軟件實現(xiàn)代碼
- Android簡單的利用MediaRecorder進行錄音的實例代碼
- Android使用AudioRecord實現(xiàn)錄音功能
相關(guān)文章
Android RecyclerView四級緩存源碼層詳細分析
RecyclerView是Android一個更強大的控件,其不僅可以實現(xiàn)和ListView同樣的效果,還有優(yōu)化了ListView中的各種不足。其可以實現(xiàn)數(shù)據(jù)縱向滾動,也可以實現(xiàn)橫向滾動(ListView做不到橫向滾動)。接下來講解RecyclerView的用法2022-11-11
Android實現(xiàn)仿360桌面懸浮清理內(nèi)存
今天給大家?guī)硪粋€仿360手機衛(wèi)士懸浮窗清理內(nèi)存的效果的教程,非常的簡單實用,需要的小伙伴可以參考下2015-12-12
Android超詳細介紹自定義多選框與點擊按鈕跳轉(zhuǎn)界面的實現(xiàn)
這篇文章主要介紹了在Android開發(fā)中如何來實現(xiàn)自定義多選框以及如何實現(xiàn)點擊按鈕跳轉(zhuǎn)界面的功能,感興趣的朋友快來看看吧2022-03-03
Android progressbar實現(xiàn)帶底部指示器和文字的進度條
這篇文章主要為大家詳細介紹了Android progressbar實現(xiàn)帶底部指示器和文字的進度條,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01

