ImageReader.SetOnImageAvailableLister抛出强制转换错误,除非活动实现IOnImageAvailableListener

时间:2017-08-14 23:57:40

标签: android xamarin.android screenshot mediaprojectionmanager

我试图封装Android屏幕的屏幕截图远离我的主要活动。我有一个实现

的类
ImageReader.IOnImageAvailableListner

但是

 imageReader.SetOnImageAvailableListener(this, null)
类中的

抛出一个强制转换异常(但不是编译异常)。我发现避免这种情况的唯一方法是让我的活动本身实现IOnImageAvailableListner。似乎Xamarin / Mono的某些部分确实要求SetOnImageAvailableListner的参数属于实现IOnImageAvailableListner的Activity类型。

这是我班级的相关部分:

    public class Screenshooter : ImageReader.IOnImageAvailableListener
    {
        public void TakeScreenshot(Context context,
                                            Result resultCode,
                                            Intent data,
                                            IOnScreenshot onScreenshotCallback)
        {
            _context = context;
            _onScreenshot = onScreenshotCallback;

            _imageAvailableCount = 0;

            var size = new Point();
            ((Activity) context).WindowManager.DefaultDisplay.GetSize(size);
            _width = size.X;
            _height = size.Y;
            _imageReader = ImageReader.NewInstance(_width, _height, ImageFormatType.Rgb565, 2);
            MediaProjectionManager mediaProjectionManager  = (MediaProjectionManager) context.GetSystemService(Context.MediaProjectionService);

            if (_mediaProjection == null)
            {
                _mediaProjection =mediaProjectionManager.GetMediaProjection((int) resultCode, data);
                if (_mediaProjection == null)
                {
                    //                    Log.e(TAG, "MediaProjection null. Cannot take the screenshot.");
                    logger.Error("MediaProjection null. Cannot take the screenshot.");
                    return;
                }
            }
            try
            {
                _virtualDisplay = _mediaProjection.CreateVirtualDisplay("Screenshotter", _width, _height, (int) context .Resources.DisplayMetrics.DensityDpi, (DisplayFlags) DisplayManager.VirtualDisplayFlagAutoMirror, _imageReader.Surface, null, null);

                /////////////   THIS IS THE LINE THAT FAILS    ////////////
                _imageReader.SetOnImageAvailableListener(this, null);
                ///////////////////////////////////////////////////////////
            }
            catch (Exception ex)
            {
                logger.Error($"Error in {nameof(TakeScreenshot)}", ex);
                throw;
            }

            return;
        }
        //IOnImageAvailableListener Members

        public void OnImageAvailable(ImageReader reader)
        {
               // do stuff
         }

...
   }

我在请求屏幕截图的活动中实例化它:

public class MainActivity : Activity
{
    private void TakeScreenshot()
    {
        StartActivityForResult(((MediaProjectionManager) GetSystemService(MediaProjectionService)).CreateScreenCaptureIntent(),
                               REQUEST_CODE);
    }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
 {
     Screenshooter.GetInstance().takeScreenShot(this, resultCode, data, callback);
}

省略完成屏幕截图后调用的回调代码。

我到处都看到了这种模式的Java android代码示例。 (具体来说,我一直在看这个例子:https://github.com/omerjerk/Screenshotter

我是Android和Xamarin的新手,但在C#方面拥有丰富的经验。

这是Xamarin中的错误吗?有解决办法吗?

由于

1 个答案:

答案 0 :(得分:0)

  

我发现避免这种情况的唯一方法是让我的活动本身实现IOnImageAvailableListner。

不,这不是唯一的方法,为了避免在活动类上实现接口,你正在创建自己的实现这个接口的类,例如:

public class MyImageReaderListener : Java.Lang.Object, ImageReader.IOnImageAvailableListener
{
    public void Dispose()
    {
        //TODO:
    }

    public void OnImageAvailable(ImageReader reader)
    {
        //TODO:
    }
}

强制转换异常是由this引起的,它引用了Activity类,而且这个类没有实现接口。如果您熟悉C#,您应该能够理解这一点,您可以在此处将this更改为您班级的新实例:

imagereader.SetOnImageAvailableListener(new MyImageReaderListener(), null);

代码如下:

Screenshotter.getInstance()
             .setSize(720, 1280)
             .takeScreenshot(this, resultCode, data, new ScreenshotCallback() {
                 @Override
                 public void onScreenshot(Bitmap bitmap) {
                     //Enjoy your bitmap
                 }
             });

C#没有这样的匿名java内部类,你可以参考Can a C# anonymous class implement an interface?。这就是为什么我们创建了一个实现接口的类。

许多演示直接在活动上实现接口的原因是有时我们需要来自侦听器的返回值来继续我们的逻辑工作,您可以检查Xamarin的Api设计为Events and Listeners