Canvas.clipPath上的Android UnsupportedOperationException

时间:2012-12-03 01:45:36

标签: android exception android-canvas

我在我的项目中使用来自此处https://github.com/lvillani/android-cropimage的图像裁剪库来裁剪存储在设备上的图像。

但是,某些用户使用以下堆栈跟踪报告崩溃

java.lang.UnsupportedOperationException
at android.view.GLES20Canvas.clipPath(GLES20Canvas.java:413)
at com.android.camera.HighlightView.draw(HighlightView.java:101)
at com.android.camera.CropImageView.onDraw(CropImage.java:783)
at android.view.View.draw(View.java:11006)
at android.view.View.getDisplayList(View.java:10445)
at android.view.ViewGroup.drawChild(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.getDisplayList(View.java:10443)
at android.view.ViewGroup.drawChild(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.getDisplayList(View.java:10443)
at android.view.ViewGroup.drawChild(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.getDisplayList(View.java:10443)
at android.view.ViewGroup.drawChild(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.getDisplayList(View.java:10443)
at android.view.ViewGroup.drawChild(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
at android.view.View.draw(View.java:11009)
at android.widget.FrameLayout.draw(FrameLayout.java:450)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2154)
at android.view.View.getDisplayList(View.java:10445)
at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:853)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:1961)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1679)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2558)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4697)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
at dalvik.system.NativeStart.main(Native Method)

从搜索开始,我认为这只是由某些设备上的硬件加速引起的。我在清单中禁用了硬件加速,但异常仍在发生。我还发现“一个可靠的解决方法是识别代码中有问题的操作,将其绘制到位图,然后将位图blit到加速画布。”

根据堆栈跟踪的有问题的代码是

protected void draw(Canvas canvas) {
    if (mHidden) {
        return;
    }
    canvas.save();
    Path path = new Path();
    if (!hasFocus()) {
        mOutlinePaint.setColor(0xFF000000);
        canvas.drawRect(mDrawRect, mOutlinePaint);
    } else {
        Rect viewDrawingRect = new Rect();
        mContext.getDrawingRect(viewDrawingRect);
        if (mCircle) {
            float width  = mDrawRect.width();
            float height = mDrawRect.height();
            path.addCircle(mDrawRect.left + (width  / 2),
                           mDrawRect.top + (height / 2),
                           width / 2,
                           Path.Direction.CW);
            mOutlinePaint.setColor(0xFFEF04D6);
        } else {
            path.addRect(new RectF(mDrawRect), Path.Direction.CW);
            mOutlinePaint.setColor(0xFFFF8A00);
        }
        canvas.clipPath(path, Region.Op.DIFFERENCE);
        canvas.drawRect(viewDrawingRect,
                hasFocus() ? mFocusPaint : mNoFocusPaint);

        canvas.restore();
        canvas.drawPath(path, mOutlinePaint);

        if (mMode == ModifyMode.Grow) {
            if (mCircle) {
                int width  = mResizeDrawableDiagonal.getIntrinsicWidth();
                int height = mResizeDrawableDiagonal.getIntrinsicHeight();

                int d  = (int) Math.round(Math.cos(/*45deg*/Math.PI / 4D)
                        * (mDrawRect.width() / 2D));
                int x  = mDrawRect.left
                        + (mDrawRect.width() / 2) + d - width / 2;
                int y  = mDrawRect.top
                        + (mDrawRect.height() / 2) - d - height / 2;
                mResizeDrawableDiagonal.setBounds(x, y,
                        x + mResizeDrawableDiagonal.getIntrinsicWidth(),
                        y + mResizeDrawableDiagonal.getIntrinsicHeight());
                mResizeDrawableDiagonal.draw(canvas);
            } else {
                int left    = mDrawRect.left   + 1;
                int right   = mDrawRect.right  + 1;
                int top     = mDrawRect.top    + 4;
                int bottom  = mDrawRect.bottom + 3;

                int widthWidth   =
                        mResizeDrawableWidth.getIntrinsicWidth() / 2;
                int widthHeight  =
                        mResizeDrawableWidth.getIntrinsicHeight() / 2;
                int heightHeight =
                        mResizeDrawableHeight.getIntrinsicHeight() / 2;
                int heightWidth  =
                        mResizeDrawableHeight.getIntrinsicWidth() / 2;

                int xMiddle = mDrawRect.left
                        + ((mDrawRect.right  - mDrawRect.left) / 2);
                int yMiddle = mDrawRect.top
                        + ((mDrawRect.bottom - mDrawRect.top) / 2);

                mResizeDrawableWidth.setBounds(left - widthWidth,
                                               yMiddle - widthHeight,
                                               left + widthWidth,
                                               yMiddle + widthHeight);
                mResizeDrawableWidth.draw(canvas);

                mResizeDrawableWidth.setBounds(right - widthWidth,
                                               yMiddle - widthHeight,
                                               right + widthWidth,
                                               yMiddle + widthHeight);
                mResizeDrawableWidth.draw(canvas);

                mResizeDrawableHeight.setBounds(xMiddle - heightWidth,
                                                top - heightHeight,
                                                xMiddle + heightWidth,
                                                top + heightHeight);
                mResizeDrawableHeight.draw(canvas);

                mResizeDrawableHeight.setBounds(xMiddle - heightWidth,
                                                bottom - heightHeight,
                                                xMiddle + heightWidth,
                                                bottom + heightHeight);
                mResizeDrawableHeight.draw(canvas);
            }
        }
    }
}

如何绘制位图然后blit到画布?

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:17)

在ICS设备上,有一个开发人员选项可以强制硬件加速,即使应用程序没有请求它也是如此。这就是导致崩溃的原因。你应该可以使用这样的东西强迫它使用软件渲染:

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
   myCusomView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

答案 1 :(得分:0)

我猜你可以将你的视图绘制到离屏位图并将位图复制到屏幕画布上。例如,

protected void draw(Canvas canvas) {
    if (mHidden) {
        return;
    }

    Bitmap bitmap = createOffScreenBitmap();
    canvas.drawa(bitmap,0f, 0f, null);

}


private Bitmap drawOffScreenBitmap(){

    // Draw whatever you want to draw right here.
}

此外,您可以使用支持硬件加速的PorterDuffxfermode,而不是clippath

答案 2 :(得分:0)

myCustomView =查看班级名称或使用this

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
   this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

我使用that方法获得解决方案。