- AndroidManifest配置
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- Android6.0后的动态权限
public static void checkPermission(AppCompatActivity activity) {
if (Build.VERSION.SDK_INT >= 23) {
int checkPermission =
ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)
+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)
+ ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
if (checkPermission != PackageManager.PERMISSION_GRANTED) {
//动态申请
ActivityCompat.requestPermissions(activity, new String[]{
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
}
}
}
-
检查权限
-
初始化
MediaProjectionManager
-
申请录制屏幕,会出现提示屏幕录制的系统弹窗
-
在
onActivityResult
拿到是否允许的结果 -
在结果成功时开启
Service
进行录制屏幕
该类代码如下
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import com.screen.recorder.demo.service.ScreenRecordService;
/**
* @author by talon, Date on 19/6/23.
* note:
*/
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 1;
private MediaProjectionManager mMediaProjectionManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermission(this); //检查权限
mMediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
}
public void StartRecorder(View view) {
createScreenCapture();
}
public void StopRecorder(View view){
Intent service = new Intent(this, ScreenRecordService.class);
stopService(service);
}
public static void checkPermission(AppCompatActivity activity) {
if (Build.VERSION.SDK_INT >= 23) {
int checkPermission =
ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)
+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)
+ ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
if (checkPermission != PackageManager.PERMISSION_GRANTED) {
//动态申请
ActivityCompat.requestPermissions(activity, new String[]{
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
}
}
}
private void createScreenCapture() {
Intent captureIntent = mMediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
try {
Toast.makeText(this, "允许录屏", Toast.LENGTH_SHORT).show();
Intent service = new Intent(this, ScreenRecordService.class);
service.putExtra("resultCode", resultCode);
service.putExtra("data", data);
startService(service);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "拒绝录屏", Toast.LENGTH_SHORT).show();
}
}
}
对应的视图代码如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始录制"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="StartRecorder"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止录制"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="StopRecorder"/>
</LinearLayout>
-
拿到传递由
onActivityResult
回调产生的resultCode
与data
-
获取手机屏幕的宽高与
dpi
-
创建
MediaProjection
MediaRecorder
VirtualDisplay
-
在
createMediaRecorder
方法中配置保存视频的信息,文件的路径、文件名、清晰度等
该类代码如下
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;
import com.screen.recorder.demo.utils.ScreenUtils;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author by talon, Date on 19/6/23.
* note:
*/
public class ScreenRecordService extends Service {
private final String TAG = "ScreenRecordService";
/**
* 是否为标清视频
*/
private boolean isVideoSd = false;
private int mScreenWidth;
private int mScreenHeight;
#### 《设计思想解读开源框架》

**第一章、 热修复设计**
* **第一节、 AOT/JIT & dexopt 与 dex2oat**
* **第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题**
* **第三节、热修复设计之热修复原理**
* **第四节、Tinker 的集成与使用(自动补丁包生成)**

**第二章、 插件化框架设计**
* **第一节、 Class 文件与 Dex 文件的结构解读**
* **第二节、 Android 资源加载机制详解**
* **第三节、 四大组件调用原理**
* **第四节、 so 文件加载机制**
* **第五节、 Android 系统服务实现原理**

**第三章、 组件化框架设计**
* **第一节、阿里巴巴开源路由框——ARouter 原理分析**
* **第二节、APT 编译时期自动生成代码&动态类加载**
* **第三节、 Java SPI 机制**
* **第四节、 AOP&IOC**
* **第五节、 手写组件化架构**

**第四章、图片加载框架**
* **第一节、图片加载框架选型**
* **第二节、Glide 原理分析**
* **第三节、手写图片加载框架实战**

**第五章、网络访问框架设计**
* **第一节、网络通信必备基础**
* **第二节、OkHttp 源码解读**
* **第三节、Retrofit 源码解析**

**第六章、 RXJava 响应式编程框架设计**
* **第一节、链式调用**
* **第二节、 扩展的观察者模式**
* **第三节、事件变换设计**
* **第四节、Scheduler 线程控制**

**第七章、 IOC 架构设计**
* **第一节、 依赖注入与控制反转**
* **第二节、ButterKnife 原理上篇、中篇、下篇**
* **第三节、Dagger 架构设计核心解密**

**第八章、 Android 架构组件 Jetpack**
* **第一节、 LiveData 原理**
* **第二节、 Navigation 如何解决 tabLayout 问题**
* **第三节、 ViewModel 如何感知 View 生命周期及内核原理**
* **第四节、 Room 架构方式方法**
* **第五节、 dataBinding 为什么能够支持 MVVM**
* **第六节、 WorkManager 内核揭秘**
* **第七节、 Lifecycles 生命周期**

**本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
*
* **第三节、 ViewModel 如何感知 View 生命周期及内核原理**
* **第四节、 Room 架构方式方法**
* **第五节、 dataBinding 为什么能够支持 MVVM**
* **第六节、 WorkManager 内核揭秘**
* **第七节、 Lifecycles 生命周期**
[外链图片转存中...(img-ZtkBBsin-1714553298990)]
**本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…**
[外链图片转存中...(img-sFPeOnLZ-1714553298990)]
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**