Android实现截屏功能

作者:爱乐写代码 时间:2022-10-25 04:36:52 

导言

目前截屏的方法很多,root不适用,要么其他方法就是有局限性,而其中官方给出的方案最好—MediaProjection

介绍

Android 5.0以后开放的录屏API,取视频中的一帧数据,这样就可以实现截屏

步骤

在activity中授权,在service中完成初始化并截图,当然可以后台定时截图,但是6.0系统会有内存溢出的bug

1:build.gradle


compileSdkVersion 21
   buildToolsVersion '27.0.3'

defaultConfig {
       applicationId "com.aile.screenshot"
       multiDexEnabled true
       minSdkVersion 21
       targetSdkVersion 21
       versionCode 1
       versionName "1.0"
   }

2:在activity中授权


public void requestCapturePermission() {
       if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
           return;
       }
       MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
       startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);
   }

@Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       super.onActivityResult(requestCode, resultCode, data);
       switch (requestCode) {
           case REQUEST_MEDIA_PROJECTION:
               if (resultCode == RESULT_OK && data != null) {
                   Service.setResultData(data);
                   startService(new Intent(this, Service.class));
                   finish();
               }
               break;
       }
   }

3:在service中初始化ImageReader,MediaProjection


private void createImageReader() {
       mImageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 1);
   }
public void setUpMediaProjection() {
       mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, mResultData);
       }
   }

4:在service中完成截图重要步骤:


private void startScreenShot() {
       Handler handler = new Handler();
       handler.postDelayed(new Runnable() {
           @Override
           public void run() {
               startVirtual();
           }
       }, 0);

handler.postDelayed(new Runnable() {
           @Override
           public void run() {
               startCapture();
           }
       }, 50);
   }
public void startVirtual() {
       if (mMediaProjection != null) {
           virtualDisplay();
       } else {
           setUpMediaProjection();
           virtualDisplay();
       }
   }
private void virtualDisplay() {
       mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror",
               mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
               mImageReader.getSurface(), null, null);
   }

//异常处理的核心
private void startCapture() {
       Image image = null;
       try {
           image = mImageReader.acquireLatestImage();
       } catch (IllegalStateException e) {
           if (null != image) {
               image.close();
               image = null;
               image = mImageReader.acquireLatestImage();
           }
       }
       if (image == null) {
           startScreenShot();
       } else {
           SaveTask mSaveTask = new SaveTask();
           AsyncTaskCompat.executeParallel(mSaveTask, image);

new Handler().postDelayed(new Runnable() {
               @Override
               public void run() {
                   stopVirtual();
                   tearDownMediaProjection();
               }
           }, 0);
       }
   }
public class SaveTask extends AsyncTask<Image, Void, Bitmap> {
       @Override
       protected Bitmap doInBackground(Image... params) {
           if (params == null || params.length < 1 || params[0] == null) {
               return null;
           }
           Image image = params[0];
           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);
           //这就是初始截图
           bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
           image.close();
           return bitmap;
       }

@Override
       protected void onPostExecute(final Bitmap bitmap) {
           super.onPostExecute(bitmap);
           //处理bitmap的业务代码
   }

5:Bitmap转IS流,指定区域截图


// 将Bitmap转换成InputStream
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
  InputStream inputStream = new ByteArrayInputStream(bos.toByteArray());
//指定区域截图
  Rect mRect = new Rect(51, 74, 58, 62);
  BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, true);
  Bitmap bm = bitmapRegionDecoder.decodeRegion(mRect, null);

6:定时任务的处理


private Timer timer = new Timer();
public void shootByTime() {
       final Handler handler = new Handler() {
           @Override
           public void handleMessage(Message msg) {
               startScreenShot();
               super.handleMessage(msg);
           }
       };
       timer.schedule(new TimerTask() {
           @Override
           public void run() {
               Message message = new Message();
               message.what = 1;
               handler.sendMessage(message);
           }
       }, 0, 100);
   }

7:横竖屏的处理


@Override
   public void onConfigurationChanged(Configuration newConfig) {
       super.onConfigurationChanged(newConfig);
       if (newConfig.orientation == this.getResources().getConfiguration().ORIENTATION_PORTRAIT) {
           mRect = new Rect(51, 775, 745, 47);
       } else if (newConfig.orientation == this.getResources().getConfiguration().ORIENTATION_LANDSCAPE) {
           mRect = new Rect(54, 24, 545, 45);
       }
   }

8:还有很多,只需按照需求走就OK,没有难的东西,需要不停的学习和积累

来源:https://blog.csdn.net/ware00/article/details/80744465

标签:Android,截屏
0
投稿

猜你喜欢

  • C#使用IComparer自定义List类实现排序的方法

    2021-06-28 04:28:09
  • Java Base64算法实际应用之邮件发送实例分析

    2022-08-08 04:00:04
  • 布隆过滤器面试如何快速判断元素是否在集合里

    2022-10-17 15:55:19
  • Android编程使用Service实现Notification定时发送功能示例

    2023-03-12 09:54:44
  • Android自定义view实现圆形、圆角和椭圆图片(BitmapShader图形渲染)

    2022-10-08 07:51:35
  • java实现新浪微博Oauth接口发送图片和文字的方法

    2023-11-29 01:43:04
  • UE4 Unlua 调用异步蓝图节点AIMoveTo函数示例详解

    2022-04-12 05:35:41
  • c# 死锁和活锁的发生及避免

    2023-05-28 00:45:49
  • 安卓(Android)动态创建多个按钮并添加监听事件

    2023-04-25 16:11:43
  • 浅谈Java中几种常见的比较器的实现方法

    2022-04-08 19:04:36
  • Android编程获取通知栏高度的方法

    2023-10-23 22:50:24
  • Javaweb开发中通过Servlet生成验证码图片

    2022-06-23 06:33:34
  • Android编程画图之抗锯齿解决方法

    2022-12-17 12:03:54
  • Android返回键功能的实现方法

    2021-10-01 12:54:53
  • Android自定义EditText实现登录界面

    2022-07-03 11:59:25
  • Spring Batch批处理框架使用解析

    2021-12-24 03:41:19
  • Spring入门实战之Profile详解

    2021-10-03 19:08:34
  • android中sqlite的按条件查找的小例子

    2021-06-18 03:39:33
  • Java使用Math.random()结合蒙特卡洛方法计算pi值示例

    2023-05-10 10:43:13
  • C#程序提示“正由另一进程使用,因此该进程无法访问该文件”的解决办法

    2022-06-27 04:34:11
  • asp之家 软件编程 m.aspxhome.com