一、使用MediaProjectionManager

Android5.0之后,开放截取屏幕的API,也就是利用MediaProjectionManager创建VirtualDisplay,传入与ImageReader关联的Surface,这样就可以从ImageReader中获取到Image,然后把Image的像素数组拷贝到Bitmap,如果要保存为图片,就用得到的Bitmap压缩为JPEG格式的图片。

首先是使用startActivityForResult发起录屏的请求:

    private void startScreenShot(){WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);if (windowManager != null) {DisplayMetrics displayMetrics = new DisplayMetrics();windowManager.getDefaultDisplay().getMetrics(displayMetrics);width = displayMetrics.widthPixels;height = displayMetrics.heightPixels;dpi = displayMetrics.densityDpi;}mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);if (mediaProjectionManager != null) {startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 123);}}

在得到用户授权录屏后,在onActivityResult中获取MediaProjection-->VirtualDisplay-->ImagReader-->Image-->Bitmap:

    @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);if (mediaProjection != null){getBitmap(mediaProjection);}}
private void getBitmap(MediaProjection mediaProjection){ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3);mediaProjection.createVirtualDisplay("screen_shot",width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,imageReader.getSurface(), null, null);imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {Image image = reader.acquireNextImage();int width = image.getWidth();int height = image.getHeight();final Image.Plane[] planes = image.getPlanes();final ByteBuffer buffer = planes[0].getBuffer();int pixelStride = planes[0].getPixelStride();int rowStride = planes[0].getRowStride();int rowPadding = rowStride - pixelStride * width;Bitmap bitmap = Bitmap.createBitmap(width+rowPadding/pixelStride, height, Bitmap.Config.ARGB_8888);bitmap.copyPixelsFromBuffer(buffer);String filePath = Environment.getExternalStorageDirectory().getPath() + "/hello.jpg";//bitmap保存为图片saveBitmap(bitmap, filePath);image.close();}}, null);}
private void saveBitmap(Bitmap bitmap, String filePath){try {FileOutputStream outputStream = new FileOutputStream(filePath);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}

优点:不用系统签名,不依赖系统底层API;

缺点:弹出确认框,需要用户授权录屏;

二、使用SurfaceControl

从上面分析可知,MediaProjectionManager录屏依赖Surface,分析Surface源码后,发现Surface其实是调用SurfaceControl,也就是说可以用SurfaceControl走捷径去截屏。其实系统框架层的截屏也是调用SurfaceControl。但是,由于SurfaceControl属于系统API,对用户不开放,我们无法直接调用。说到这里,大家应该都想到,用反射机制来调用。

正确的调用方式是这样的:

Bitmap bitmap = SurfaceControl.screenshot(width, height);

通过系统源码,可以知道它在Android.view.SurfaceControl路径下。既然路径、类、方法、参数都知道了,反射就没问题:

 //使用反射调用截屏private void screenShotByReflect(){DisplayMetrics mDisplayMetrics = new DisplayMetrics();float[] dims = { mDisplayMetrics.widthPixels,mDisplayMetrics.heightPixels };try {Class<?> demo = Class.forName("android.view.SurfaceControl");Method method = demo.getDeclaredMethod("screenshot", int.class,int.class);mScreenBitmap = (Bitmap) method.invoke(null,(int) dims[0],(int) dims[1]);} catch (Exception e) {e.printStackTrace();}}

在调用截屏之前,判断屏幕是否发生旋转:

 private Bitmap takeScreenshot() {mDisplay.getRealMetrics(mDisplayMetrics);float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};float degrees = getDegreesForRotation(mDisplay.getRotation());boolean requiresRotation = (degrees > 0);//如果屏幕发生旋转,通过matrix旋转回来if (requiresRotation) {mDisplayMatrix.reset();mDisplayMatrix.preRotate(-degrees);mDisplayMatrix.mapPoints(dims);dims[0] = Math.abs(dims[0]);dims[1] = Math.abs(dims[1]);}//调用截屏screenShotByReflect();return mScreenBitmap;}

优点:不用弹框授权,不用系统签名;

缺点:使用反射机制,如果系统API或者方法发生更改,导致无法调用;

三、使用screencap的adb命令

命令行是这样的:adb shell screencap -p file_path

在代码中执行,就不用adb shell,直接screencap -p file_path,调用Runtime的进程来执行:

 public static void screenShotByShell(String filePath){String shotCmd = "screencap -p " + filePath + " \n";try {Runtime.getRuntime().exec(shotCmd);} catch (IOException e) {e.printStackTrace();}}

优点:代码简单,直接获取到图片;

缺点:需要系统签名;

以上三种截屏方式,大家可以根据应用场景来使用。如果是用户app,需要连续录屏,建议采用MediaProjectionManager;如果是希望得到单个Bitmap,那么可以用SurfaceControl;如果是系统app,并且希望得到图片,首选screencap的adb命令行。

Android三种方式截取任意界面屏幕相关推荐

  1. android圆形点击效果,Android 三种方式实现自定义圆形页面加载中效果的进度条

    [实例简介] Android 三种方式实现自定义圆形页面加载中效果的进度条 [实例截图] [核心代码] ad376a86-a9aa-49bc-8cea-321bcff2c0c3 └── AnimRou ...

  2. Android源码编译:任意界面屏幕边缘上滑弹出快捷操作栏【一键加速、开关控制】

    <The Fucking Source Code> 注:以下均为android源码Framework层修改. 设计实现在任意界面从屏幕边缘上滑弹出快捷操作栏,包括亮度调节.正在后台运行的程 ...

  3. Android 三种方式实现自定义圆形页面加载中效果的进度条

    转载:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=76872 一.通过动画实现 定义res/anim/loading.xml如 ...

  4. Android 三种方式播放视频和百度直播

    一.Android视频播放这里做个简单介绍,视频播放主要有三种方式:安卓7.0以上兼容 (获取本地应用assets raw文件位置:"file:///android_asset/文件名&qu ...

  5. android 气泡.9,Android 三种方式实现三角形气泡效果、自定义View、shape、点9图

    背景 这期需求中,项目需要这样一个情况,就是二级菜单上面有个三角形 乍一看,用个图片就可以解决,一个线性布局.垂直摆下去,所以一开始我是这样尝试的,后来发现美工给我切的图很不合适,不同手机显示效果也不 ...

  6. Android:按键响应方式第一种onClick属性,第二种方法接口类,第三种方式匿名内部类,第四种方式Activity

    一.在xml 中设置按键的onClick 绑定的函数 新建一个工程 然后在相关的页面添加一个Button 运行一下 实际上,现在这个按键一,我们去运行的时候,他是没有任何的反馈的,我们按完它,他没有任 ...

  7. android音频开发6,Android 音视频开发(一) : 通过三种方式绘制图片

    想要逐步入门音视频开发,就需要一步步的去学习整理,并积累.本文是音视频开发积累的第一篇. 对应的要学习的内容是:在 Android 平台绘制一张图片,使用至少 3 种不同的 API,ImageView ...

  8. android sqlite使用之模糊查询数据库数据的三种方式

    android sqlite使用之模糊查询数据库数据的三种方式 android应用开发中常常需要记录一下数据,而在查询的时候如何实现模糊查询呢?很少有文章来做这样的介绍,所以这里简单的介绍下三种sql ...

  9. 三种方式让 Android WebView 支持文件下载

    三种方式让 Android WebView 支持文件下载 最近在开发的过程中遇到一个需求,那就是让 WebView 支持文件下载,比如说下载 apk.WebView 默认是不支持下载的,需要开发者自己 ...

最新文章

  1. python面试总结 博客园_python面试题总结
  2. 预训练模型参数重载必备!
  3. 基于 Annotation 拦截的 Spring AOP 权限验证方法
  4. mysql修改存储位置及开启远程
  5. HQL语句使用row_number() over(partition by),分组排序取topN
  6. activity绑定service
  7. spark sql建表的异常
  8. 因子(factor)的研究
  9. 交通仿真软件测试自学,交通仿真及常用的仿真软件简介
  10. 档案盒正面标签制作_使用WORD制作档案盒侧面标签方法
  11. 有监督的SAR变化检测公开数据集
  12. 项目(百万并发网络通信架构)10.3---send()函数的极限测试
  13. HTML5系列代码:框模型的大小
  14. 【Word】长文档排版
  15. 什么是编译程序(含翻译程序、解释程序和中间代码的定义介绍)
  16. imperva ssl加速卡查询
  17. 微信支付签名失败(几种解决方案)
  18. 电路中的VCC是什么意思?
  19. Matlab读取Zygo干涉仪dat数据文件 光学检测加工(明码需另付费)
  20. part01.03 委托与 Lambda 表达式(三):Lambda 表达式

热门文章

  1. 使您的软件运行起来: 了解有关缓冲区溢出方面的基础知识
  2. Edge打不开中国知网的一次经历
  3. 淘宝API接口:upload_img - 上传图片到淘宝
  4. bc计算A股上市新股依次涨停股价
  5. office老是提示Microsoft office word 遇到问题需要关闭。还问是否发送错误报告。
  6. 男人穿衣的20条黄金法则
  7. 【观察】中国移动“加持”之后,紫光云未来的升势与胜势
  8. linux unicode 转换工具,字符集之间转换(UTF-8,UNICODE,Gb2312)
  9. Win10升级11错误代码80070002/无法判断你的电脑是否有足够空间继续安装windows11
  10. XT711 WIFI连接正常 却无法上网的解决办法