Display
类display.getRotation() // 获取屏幕方向(横屏/竖屏)
display.getRefreshRate() // 获取屏幕刷新率(如:60Hz)
Point
类public class Point {
public int x; // 横坐标
public int y; // 纵坐标
}
int
变量更规范// 像素转dp(适配不同密度屏幕)
float dp = px / (getResources().getDisplayMetrics().density);
完整代码
// 在Activity的onCreate方法中获取屏幕尺寸
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取屏幕尺寸
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size); //把屏幕的大小记录到size的x和y上面
int screenWidth = size.x;
int screenHeight = size.y;
// 实际应用:设置TextView显示尺寸
TextView sizeInfo = findViewById(R.id.tv_size);
sizeInfo.setText("屏幕宽度:" + screenWidth + "px\n屏幕高度:" + screenHeight + "px");
// 打印到Logcat
Log.d("ScreenSize", "宽度:" + screenWidth + " 高度:" + screenHeight);
}
ImageReader
// 参数说明:
// 宽度 | 高度 | 图像格式 | 最大缓存图像数(建议2-3)
ImageReader imageReader = ImageReader.newInstance(
1080,
1920,
ImageFormat.YUV_420_888,
3);
width x height
个像素点组成// 1. 创建文件路径
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"screenshot_" + System.currentTimeMillis() + ".png");
// 2. 保存Bitmap到该路径
try (FileOutputStream out = new FileOutputStream(file)) {
// 将 Bitmap 以 PNG 格式压缩并保存到文件中
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
Toast.makeText(this, "保存成功:" + file.getPath(), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
/sdcard/Pictures/
/内部存储/DCIM/Pictures/
"screenshot_" + System.currentTimeMillis() + ".png"
System.currentTimeMillis()
获取1970年至今的毫秒数(如 1625043725123
)screenshot_1625043725123.png
createVirtualDisplay
的作用是创建一个虚拟的屏幕镜像
想象你有一台手机,现在要把它屏幕上的内容实时投影到另一台设备上。createVirtualDisplay
就相当于在这台手机内部安装了一个隐藏的摄像头,这个摄像头会持续拍摄屏幕内容,并将画面传递给处理单元(例如保存为图片或视频)。
// 初始化ImageReader(接收画面)
ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);
// 创建虚拟显示屏绑定到ImageReader
virtualDisplay = mediaProjection.createVirtualDisplay(...);
// 从ImageReader获取图像
Image image = imageReader.acquireLatestImage();
Bitmap bitmap = imageToBitmap(image); // 转换为Bitmap
把虚拟屏幕展示传送给图片读取器的surface
imageReader.getSurface()
// 创建虚拟显示屏
virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture",
width, height, getResources().getDisplayMetrics().densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
imageReader.getSurface(), null, null);
完整代码
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.Environment;
import android.view.Display;
import android.view.Surface;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
// 主活动类,继承自 AppCompatActivity
public class MainActivity extends AppCompatActivity {
// 屏幕捕获权限请求码
private static final int REQUEST_CODE_SCREEN_CAPTURE = 1;
// 写入外部存储权限请求码
private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 2;
// MediaProjectionManager 实例,用于管理屏幕投影
private MediaProjectionManager mediaProjectionManager;
// MediaProjection 实例,用于实际的屏幕投影操作
private MediaProjection mediaProjection;
// ImageReader 实例,用于读取屏幕图像
private ImageReader imageReader;
// VirtualDisplay 实例,用于创建虚拟显示屏
private VirtualDisplay virtualDisplay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 通过系统服务获取 MediaProjectionManager 实例
mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
// 检查是否有写入外部存储的权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// 若没有权限,请求写入外部存储权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_WRITE_EXTERNAL_STORAGE);
} else {
// 若已有权限,请求屏幕捕获权限
requestScreenCapturePermission();
}
}
// 请求屏幕捕获权限的方法
private void requestScreenCapturePermission() {
// 创建屏幕捕获的 Intent
Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent();
// 启动 Intent 并等待用户授权,使用请求码 REQUEST_CODE_SCREEN_CAPTURE
startActivityForResult(captureIntent, REQUEST_CODE_SCREEN_CAPTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 检查请求码是否为屏幕捕获请求码
if (requestCode == REQUEST_CODE_SCREEN_CAPTURE) {
if (resultCode == Activity.RESULT_OK) {
// 若用户授予了屏幕捕获权限,通过 MediaProjectionManager 获取 MediaProjection 实例
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
// 开始屏幕捕获操作
startScreenCapture();
} else {
// 若用户拒绝了屏幕捕获权限,显示提示信息
Toast.makeText(this, "屏幕捕获权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
// 开始屏幕捕获的方法
private void startScreenCapture() {
// 获取默认显示屏对象
Display display = getWindowManager().getDefaultDisplay();
// 创建一个 Point 对象用于存储屏幕尺寸
Point size = new Point();
// 获取屏幕的尺寸并存储到 Point 对象中
display.getSize(size);
// 获取屏幕的宽度
int width = size.x;
// 获取屏幕的高度
int height = size.y;
// 创建 ImageReader 实例,用于读取屏幕图像
imageReader = ImageReader.newInstance(width, height, ImageFormat.RGB_565, 2);
// 为 ImageReader 设置图像可用监听器
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
// 从 ImageReader 中获取最新的图像
image = reader.acquireLatestImage();
if (image != null) {
// 获取图像的平面数组
Image.Plane[] planes = image.getPlanes();
// 获取第一个平面的 ByteBuffer
ByteBuffer buffer = planes[0].getBuffer();
// 获取像素步长
int pixelStride = planes[0].getPixelStride();
// 获取行步长
int rowStride = planes[0].getRowStride();
// 计算行填充
int rowPadding = rowStride - pixelStride * width;
// 创建一个 Bitmap 对象,用于存储图像数据
Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.RGB_565);
// 将 ByteBuffer 中的数据复制到 Bitmap 中
bitmap.copyPixelsFromBuffer(buffer);
// 裁剪 Bitmap 去除多余的填充
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
// 保存截图到文件
saveBitmapToFile(bitmap);
// 关闭 Image 对象,释放资源
image.close();
}
} catch (Exception e) {
// 若出现异常,打印异常信息
e.printStackTrace();
} finally {
if (image != null) {
// 确保 Image 对象被关闭
image.close();
}
}
}
}, null);
// 创建虚拟显示屏
virtualDisplay = mediaProjection.createVirtualDisplay("ScreenCapture",
width, height, getResources().getDisplayMetrics().densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
imageReader.getSurface(), null, null);
}
// 保存 Bitmap 到文件的方法
private void saveBitmapToFile(Bitmap bitmap) {
// 创建一个文件对象,指定保存路径和文件名
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"screenshot_" + System.currentTimeMillis() + ".png");
try (FileOutputStream fos = new FileOutputStream(file)) {
// 将 Bitmap 以 PNG 格式压缩并保存到文件中
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
// 显示保存成功的提示信息
Toast.makeText(this, "截图已保存到 " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
// 若保存过程中出现异常,打印异常信息并显示保存失败的提示信息
e.printStackTrace();
Toast.makeText(this, "保存截图失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// 检查请求码是否为写入外部存储权限请求码
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 若权限授予成功,请求屏幕捕获权限
requestScreenCapturePermission();
} else {
// 若权限授予失败,显示提示信息
Toast.makeText(this, "写入外部存储权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (virtualDisplay != null) {
// 释放虚拟显示屏资源
virtualDisplay.release();
}
if (mediaProjection != null) {
// 停止 MediaProjection 操作
mediaProjection.stop();
}
if (imageReader != null) {
// 关闭 ImageReader 资源
imageReader.close();
}
}
}
123