【问题标题】:SurfaceView onMeasure() did not set the measured dimension by calling setMeasuredDimension()SurfaceView onMeasure() 没有通过调用 setMeasuredDimension() 设置测量尺寸
【发布时间】:2015-01-19 08:16:39
【问题描述】:

我有一个 SurfaceView。我只是从另一个线程手动绘制它。

它运行良好。但是在平均运行 10-20 分钟后,我得到了这个异常:

01-14 08:51:25.000    3740-3740/com.myPackage E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.IllegalStateException: onMeasure() did not set the measured dimension by calling setMeasuredDimension()
            at android.view.View.measure(View.java:15200)
            at android.widget.RelativeLayout.measureChild(RelativeLayout.java:602)
            at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:415)
            at android.view.View.measure(View.java:15195)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4823)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at android.view.View.measure(View.java:15195)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4823)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1390)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
            at android.view.View.measure(View.java:15195)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4823)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2340)
            at android.view.View.measure(View.java:15195)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1850)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1102)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1275)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4216)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
            at android.view.Choreographer.doCallbacks(Choreographer.java:555)
            at android.view.Choreographer.doFrame(Choreographer.java:525)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4813)
            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:792)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:559)
            at dalvik.system.NativeStart.main(Native Method)

Android 文档说:
测量视图及其内容以确定测量的宽度和测量的高度。此方法由 measure(int, int) 调用,应由子类覆盖以提供对其内容的准确有效的测量。

我认为谷歌的原始实现是这样的:

@Override
    protected void More ...onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = getDefaultSize(mRequestedWidth, widthMeasureSpec);
        int height = getDefaultSize(mRequestedHeight, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

我不知道我还应该在这里实现什么。

我认为表面视图的大小永远不会改变。

注意:
我的 SurfaceView 包含在 RelativeLayout 中。
异常被一个孩子调用,但它是一个视图(异常中的第 3 行)

如果您知道如何解决这个烦人的错误,请帮助我。

编辑:
在 Activity 的 onCreate 中,我从代码中设置了我的视图(即 SurfaceView 的扩展形式)的大小

回答评论:
这就是我为所需大小设置一些公共字段的方式:

Parameters.initialize(getResources().getDisplayMetrics().widthPixels,
                getResources().getDisplayMetrics().heightPixels);

Parameters.initialize:

public static void initialize(int screenWidth, int screenHeight){
    FIELD_WIDTH = screenWidth;
    FIELD_HEIGHT = (int)(0.92f * screenHeight);
}

MyView 是用 xml 编写的。
然后我在上面设置了一些东西:

public class MyViewManager {
    protected MyView mMyView;

    public FieldPainterComp(MainActivity activity) {
        super(activity);
        initialize();
    }

    private void initialize(){
        mMyView= (MyView) activity.findViewById(R.id.vMyView);
        mMyView.getLayoutParams().height = Parameters.FIELD_HEIGHT;
        mMyView.getLayoutParams().width = Parameters.FIELD_WIDTH;
    }
}

这整个过程发生在开始。

android:screenOrientation="landscape"

屏幕永远不会变暗。游戏正在运行,只是异常来了。
我应该在某处调用测量吗?
我不明白为什么过了很久才发生

必须与此相关的其他一些例外情况:

01-19 11:53:39.812  29666-31881/com.mypackage V/GAV4﹕ Thread[disconnect check,5,main]: Disconnecting due to inactivity
01-19 11:53:39.812  29666-31881/com.mypackage V/GAV4﹕ Thread[disconnect check,5,main]: Disconnected from service
01-19 11:57:17.732  29666-29666/com.mypackage D/AndroidRuntime﹕ Shutting down VM
01-19 11:57:17.732  29666-29666/com.mypackage W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x420face0)
01-19 11:57:17.812  29666-29666/com.mypackage V/GAV4﹕ Thread[main,5,main]: Tracking Exception: IllegalStateException (@View:measure:16533) {main}
01-19 11:57:17.832  29666-29666/com.mypackage V/GAV4﹕ Thread[main,5,main]: Dispatch call queued. Dispatch will run once initialization is complete.
01-19 12:19:27.982  29666-29670/com.mypackage I/dalvikvm﹕ threadid=3: reacting to signal 3
01-19 12:19:28.262  29666-29670/com.mypackage I/dalvikvm﹕ Wrote stack traces to '/data/anr/traces.txt'
01-19 12:19:32.452  29666-29666/com.mypackage A/libc﹕ Fatal signal 6 (SIGABRT) at 0x0000025a (code=0), thread 29666 (ames.adaptation)

GAV - 是谷歌分析的东西。

我提出了另一个关于 ANR 的问题:ANR with 3 threads - using locks

【问题讨论】:

  • 是自定义视图会导致这个错误吗?
  • 是的,我从 SurfaceView 扩展。我 99% 确定 SurfaceView 会导致问题,因为在我添加 SurfaceView 后该错误开始出现(另外我在描述中添加了更多注释)
  • 您是否覆盖了onMeasure()
  • 不,因为我会做和原来的实现一样的事情(和我上面描述的一样)
  • 如何改变视图的大小?如果您在不调用 onMeasure() 的情况下更改视图边界,则框架不知道如何绘制它们。当屏幕方向改变并且必须重新绘制视图时,可能是由配置更改引起的。配置更改也会调用您的活动的 onCreate。

标签: android surfaceview onmeasure


【解决方案1】:
setMeasuredDimension()

必须在 onMeasure() 方法内部调用。我有一个类似的问题,逻辑没有达到 setMeasuredDimension()。无论之前的 if/else 语句是什么,我都解决了它强制调用 setMeasuredDimension() 的问题。

【讨论】:

    【解决方案2】:

    你使用 Fragment 并且不要在第一行写这行

    super.onCreate(savedInstanceState);
    

    【讨论】:

      【解决方案3】:

      private double aspectRatio = 1.0;

      私有布尔 isCalledRecreate = true;

      onMeasure中::- double localRatio = aspectRatio;

          if (localRatio == 0.0) {
              super.onMeasure(widthSpec, heightSpec);
      
          } else {
              int lockedWidth = MeasureSpec.getSize(widthSpec);
              int lockedHeight = MeasureSpec.getSize(heightSpec);
      
              if (lockedWidth == 0 && lockedHeight == 0) {
      
                  widthSpec = MeasureSpec.makeMeasureSpec((int) (basicWidth), MeasureSpec.AT_MOST);
                  heightSpec = MeasureSpec.makeMeasureSpec((int) (basicHeight), MeasureSpec.AT_MOST);
      
                  lockedWidth = MeasureSpec.getSize(widthSpec);
                  lockedHeight = MeasureSpec.getSize(heightSpec);
      
                  Log.i(TAG, "onMeasure: onMeasure");
      
                  callForRecreate();
              }
      
              // Get the padding of the border background.
              int hPadding = getPaddingLeft() + getPaddingRight();
              int vPadding = getPaddingTop() + getPaddingBottom();
      
              // Resize the preview frame with correct aspect ratio.
              lockedWidth -= hPadding;
              lockedHeight -= vPadding;
      
              if (lockedHeight > 0 && (lockedWidth > lockedHeight * localRatio)) {
                  lockedWidth = (int) (lockedHeight * localRatio + .5);
              } else {
                  lockedHeight = (int) (lockedWidth / localRatio + .5);
              }
      
              // Add the padding of the border.
              lockedWidth += hPadding;
              lockedHeight += vPadding;
      
              // Ask children to follow the new preview dimension.
              super.onMeasure(MeasureSpec.makeMeasureSpec(lockedWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(lockedHeight, MeasureSpec.EXACTLY));
      

      注意:- callForRecreate() 你必须创建或重新启动活动

      【讨论】:

        【解决方案4】:

        请务必致电 super.onMeasure(widthMeasureSpec,heightMeasureSpec); //例如 @覆盖 受保护的无效onMeasure(int widthMeasureSpec,int heightMeasureSpec){ super.onMeasure(widthMeasureSpec,heightMeasureSpec); //然后你的代码 }

        【讨论】:

          猜你喜欢
          • 2017-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-30
          • 1970-01-01
          • 2012-06-20
          • 1970-01-01
          相关资源
          最近更新 更多