Android截屏时间久会卡顿的问题

需求:隔3秒截一次屏
问题:运行时间在5-6分钟以后,手机会有明显卡顿现象。
关键截屏代码(隔3秒调用一次cap方法):

    private void cap() {
        //start capture reader
        mImageReader = ImageReader.newInstance(mWidth, mHeight,
                PixelFormat.RGBA_8888, 2);

        mVirtualDisplay = mediaProjection.createVirtualDisplay(
                "ScreenShot",
                mWidth,
                mHeight,
                80,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                mImageReader.getSurface(),
                null,
                handler);

        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Log.e("PTDEBUG", "new image");
                Image image = null;
                FileOutputStream fos = null;
                Bitmap bitmap = null;

                try {
                    image = reader.acquireLatestImage();
                    if (image != null) {
                        Image.Plane[] planes = image.getPlanes();
                        ByteBuffer buffer = planes[0].getBuffer();
                        int pixelStride = planes[0].getPixelStride();
                        int rowStride = planes[0].getRowStride();
                        int rowPadding = rowStride - pixelStride * mWidth;

                        bitmap = Bitmap.createBitmap(mWidth + rowPadding / pixelStride,
                                mHeight, Bitmap.Config.ARGB_8888);
                        bitmap.copyPixelsFromBuffer(buffer);

                        Date currentDate = new Date();
                        SimpleDateFormat date = new SimpleDateFormat("yyyyMMddhhmmss");
                        String fileName = mSamplePath + "temp.png";
                        fos = new FileOutputStream(fileName);
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
                        mImageReader.setOnImageAvailableListener(null, null);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (fos != null) {
                        try {
                            fos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (bitmap != null) {
                        bitmap.recycle();
                    }
                    if (image != null) {
                        image.close();
                    }
                }

            }
        }, handler);
        mediaProjection.registerCallback(new MediaProjection.Callback() {
            @Override
            public void onStop() {
                super.onStop();
            }
        }, handler);
    }

问题分析:5-6分钟后,手机出现卡顿,肯定和手机内存有关系,说明代码这一块有内存无法正常释放的问题。
尝试解决方法:

  1. mImageReader 或 mVirtualDisplay对象只初始化一次,截图只有第一次有效,再反复调用cap方法时,并不会生成最新图片,无法满足需求。
  2. 尝试回收一些变量,在mImageReader.setOnImageAvailableListener(null, null);下面加入一行mVirtualDisplay.release();,发现可以正常满足需求,运行5-6分钟后也再无卡顿现象出现。看来是mVirtualDisplay的问题。可能原因是每次调用cap方法时,都会新生成一个mVirtualDisplay对象,但是原来那个mVirtualDisplay还存在,导致OOM的问题。

解决方法:
在适当的位置回收mVirtualDisplay,修复后的代码:

    private void cap() {
        //start capture reader
        mImageReader = ImageReader.newInstance(mWidth, mHeight,
                PixelFormat.RGBA_8888, 2);

        mVirtualDisplay = mediaProjection.createVirtualDisplay(
                "ScreenShot",
                mWidth,
                mHeight,
                80,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                mImageReader.getSurface(),
                null,
                handler);

        mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Log.e("PTDEBUG", "new image");
                Image image = null;
                FileOutputStream fos = null;
                Bitmap bitmap = null;

                try {
                    image = reader.acquireLatestImage();
                    if (image != null) {
                        Image.Plane[] planes = image.getPlanes();
                        ByteBuffer buffer = planes[0].getBuffer();
                        int pixelStride = planes[0].getPixelStride();
                        int rowStride = planes[0].getRowStride();
                        int rowPadding = rowStride - pixelStride * mWidth;

                        bitmap = Bitmap.createBitmap(mWidth + rowPadding / pixelStride,
                                mHeight, Bitmap.Config.ARGB_8888);
                        bitmap.copyPixelsFromBuffer(buffer);

                        Date currentDate = new Date();
                        SimpleDateFormat date = new SimpleDateFormat("yyyyMMddhhmmss");
                        String fileName = mSamplePath + "temp.png";
                        fos = new FileOutputStream(fileName);
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
                        mImageReader.setOnImageAvailableListener(null, null);
                        mVirtualDisplay.release();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (fos != null) {
                        try {
                            fos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (bitmap != null) {
                        bitmap.recycle();
                    }
                    if (image != null) {
                        image.close();
                    }
                }

            }
        }, handler);
        mediaProjection.registerCallback(new MediaProjection.Callback() {
            @Override
            public void onStop() {
                super.onStop();
            }
        }, handler);
    }

你可能感兴趣的:(Android截屏时间久会卡顿的问题)