Android(安卓)截图和录屏
一、Android 截图
Android 截图在这里分为三类:
- 截取除状态栏的屏幕
- 截取某个控件或区域
- 使用 MediaProjection 截图
1.截取除状态栏的屏幕
该方式是使用 View 的 Cache 机制生成 View 的图像缓存保存为 Bitmap。
主要的 API 如下:
-
void setDrawingCacheEnabled(boolean flag)
开启或关闭 View 的 Cache,设置为 false 后,系统也会自动把原来的 Cache 销毁。 -
void buildDrawingCache()
创建 Cache,可不调用 -
Bitmap getDrawingCache()
获取 View 的 Cache 图片 -
void destroyDrawingCache()
销毁 Cache 。若想更新 Cache,必须要调用该方法把旧的 Cache 销毁,才能建立新的。
示例代码
View dView = getWindow().getDecorView(); dView.setDrawingCacheEnabled(true); dView.buildDrawingCache(); Bitmap bitmap = Bitmap.createBitmap(dView.getDrawingCache()); if(bitmap != null){ imageView.setImageBitmap(bitmap); } dView.setDrawingCacheEnabled(false);
2.截取某个控件或区域
该方式的原理和上面一样,都是利用 View 的 Cache 机制,不同点在于,这里的 View 不是 DecorView
示例代码:
View view = ivSrc; view.setDrawingCacheEnabled(true); view.buildDrawingCache(); Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache()); if (bitmap != null) { imageView.setImageBitmap(bitmap); } view.setDrawingCacheEnabled(false);
还有一种方式是将 View 绘制到 Canvas
View view = ivSrc; //根据 View 的宽高创建 Bitmap 对象 Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888); //将以上创建的 Bitmap 指定为要绘制的 Bitmap 作为参数创建画布 Canvas canvas = new Canvas(bitmap); //将 View 绘制在画布上 view.draw(canvas); imageView.setImageBitmap(bitmap);
ListView、ScrollView、WebView、RecyclerView 截长图都可以用使用此方法
3、使用 MediaProjection
Android 在5.0 之后支持了实时录屏的功能。通过实时录屏我们可以拿到截屏的图像。
大体步骤如下:
- 初始化一个
MediaProjectionManager
对象
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
- 创建并启动 Intent
Intent captureIntent = mediaProjectionManager.createScreenCaptureIntent(); startActivityForResult(captureIntent, RECORD_REQUEST_CODE);
- 在 Activity 的
onActivityResult
方法中获取 'MediaProjection' 对象
MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
- 创建 ImageReader 对象
//参数1:默认图像的宽度像素//参数2:默认图像的高度像素//参数3:图像的像素格式//参数4:用户想要读图像的最大数量ImageReader imageReader = ImageReader.newInstance(metrics.widthPixels, metrics.heightPixels,PixelFormat.RGBA_8888, 1);
ImageReader 类允许应用程序直接访问呈现表面的图像数据创建 ImageReader 对象
主要操作:
-
getSurface()
//得到一个表面,可用于生产这个 ImageReader 的图像 -
acquireLatestImage()
//从ImageReader的队列获得最新的图像,放弃旧的图像。 -
acquireNextImage()
//从ImageReader的队列获取下一个图像 -
getMaxImages()
//最大数量的图像 -
getWidth()
//每个图像的宽度,以像素为单位。 -
getHeight()
//每个图像的高度,以像素为单位。 -
getImageFormat()
//图像格式 -
close()
//释放与此ImageReader相关的所有资源。用完记得关 -
setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler)
//注册一个监听器,当ImageReader有一个新的Image变得可用时候调用。
- 通过
MediaProjection
创建VirtualDisplay
对象,把内容渲染给ImageRaeder
的Surface
控件
mediaProjection.createVirtualDisplay("Capture", metrics.widthPixels, metrics.heightPixels, 2, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, null);
VirtualDisplay 类代表一个虚拟显示器,调用 createVirtualDisplay() 方法,将虚拟显示器的内容渲染在一个 Surface 控件上,当进程终止时虚拟显示器会被自动的释放,并且所有的 Window 都会被强制移除。当不再使用他时,你应该调用 release() 方法来释放资源。
- 通过 ImageReader 获取 Image 生成 Bitmap
new Thread(){ @Override public void run() { while (true) { Image image = imageReader.acquireNextImage(); //8、 if (image != null) { Image.Plane[] plane = image.getPlanes(); ByteBuffer buffers = plane[0].getBuffer(); int pixelStride = plane[0].getPixelStride(); int rowStride = plane[0].getRowStride(); int rowPadding = rowStride - pixelStride * metrics.widthPixels; Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels + rowPadding / pixelStride, metrics.heightPixels, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(buffers); FileUtils.saveBitmap(bitmap); image.close(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start();
Image 为图片数据,Plane 为 Image 的抽象内部类,
image.getPlanes()
获取该图片的像素矩阵,返回值为一个 Plane[] 矩阵
plane.getBuffer()
获取图像数据,getPixelStride()
和 getRowStride()
为获取 Iamge 的一些跨距,经过一系列转换得到图像的尺寸,创建 Bitmap 对象,然后从 Image 的 ByteBuffer 中拷贝像素数据生成 Bitmap
二、MediaProjection 录屏
录屏的实现需要使用 MediaRecoder 类
前面几步同截图类似
1. 初始化一个 MediaProjectionManager
对象
2. 创建并启动 Intent
3. 在 Activity 的 onActivityResult 方法中获取 MediaProjection
对象
4. 初始化 MediaRecorder并准备录制
private void initRecorder() { mediaRecorder = new MediaRecorder(); width = displayMetrics.widthPixels; height = displayMetrics.heightPixels; dpi = displayMetrics.densityDpi; // 视频最大的尺寸 720 * 1280 ,其他视频尺寸使用屏幕大小 if (dpi > DisplayMetrics.DENSITY_XHIGH) { width = (orientation == Configuration.ORIENTATION_LANDSCAPE ? 1280 : 720); height = (orientation == Configuration.ORIENTATION_LANDSCAPE ? 720 : 1280); } //如果是横屏,视频输出时旋转90度 mediaRecorder.setOrientationHint(orientation != Configuration.ORIENTATION_LANDSCAPE ? 0 : 90); // 音频源,这里需要 android.permission.RECORD_AUDIO 权限 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); // 视频来源 mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); // 视频输出格式 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 录制输出文件 currentVideoFilePath = getRecorderDir(); mediaRecorder.setOutputFile(currentVideoFilePath); //视频编码格式 mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //音频编码格式 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 设置最大时长5分钟 mediaRecorder.setMaxDuration(1 * 60 * 1000); // 设置视频文件的比特率,经过测试该属性对于视频大小影响最大 mediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024); //设置视频分辨率 mediaRecorder.setVideoSize(width, height); //设置视频帧频率 mediaRecorder.setVideoFrameRate(30); // 录制发生错误的监听 mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { @Override public void onError(MediaRecorder mr, int what, int extra) { } }); //记录录制时出现的信息事件 mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { @Override public void onInfo(MediaRecorder mr, int what, int extra) { } }); try { //准备录制 mediaRecorder.prepare(); } catch (IOException e) { e.printStackTrace(); } }
5. 创建 VirtualDisplay
以进行录屏
virtualDisplay = mediaProjection.createVirtualDisplay("MainScreen", width, height, dpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null);
把 VirtualDisplay
的渲染目标 Surface
设置为 MediaRecorder
的 getSurface
,后面我就可以通过 MediaRecorder
将屏幕内容录制下来
6、开始录制
mediaRecorder.start();
7、停止录制
mediaRecorder.stop();mediaRecorder.reset();
更多相关文章
- Android(安卓)核心分析 -----IPC框架分析 Binder,Service,Service
- Android(安卓)framework层JNI的使用浅析
- Android(安卓)屏幕适配--最小宽度限定符适配
- Android基于Java反射机制的简单ORM-Dao层
- Android(安卓)Java层UI渲染实现一(Context的创建)
- 一篇文章看明白 Android(安卓)图形系统 Surface 与 SurfaceFling
- android内存泄露调试
- Android(安卓)Context简介
- 对Android(安卓)中坐标系的理解