在Robolectric中,如何解决DrawerLayout必须使用MeasureSpec.EXACTLY进行测量的错误?

19

我正在尝试为我的应用程序添加一个DrawerLayout来进行导航,并使用Robolectric测试我的应用程序(我发现这个问题在Robolectric 2.1.1和2.1-SNAPSHOT - 2.2-20130712.161723-17中都有出现)

我正在使用以下xml作为我的抽屉布局的基础。当我在抽屉布局上将andioid:layout_width或android:layout_height设置为"match_parent"时,我会在Robolectric中遇到错误。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- The navigation drawer -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="#D8D8D8"
        android:dividerHeight="1dp"
        android:background="#F2F2F2"/>
</android.support.v4.widget.DrawerLayout>

这是我遇到的错误的堆栈跟踪:

java.lang.IllegalArgumentException: DrawerLayout must be measured with MeasureSpec.EXACTLY.
    at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:591)
    at android.view.View.measure(View.java:15172)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4816)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:15172)
    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:4214)
    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$FrameHandler.handleMessage(Choreographer.java:657)
    at org.robolectric.shadows.ShadowHandler.routeMessage(ShadowHandler.java:125)
    at org.robolectric.shadows.ShadowHandler.access$100(ShadowHandler.java:25)
    at org.robolectric.shadows.ShadowHandler$1.run(ShadowHandler.java:110)
    at org.robolectric.util.Scheduler$PostedRunnable.run(Scheduler.java:162)
    at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:107)
    at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:92)
    at org.robolectric.util.Scheduler.advanceToLastPostedRunnable(Scheduler.java:68)
    at org.robolectric.util.Scheduler.unPause(Scheduler.java:25)
    at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:219)
    at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:258)
    at org.robolectric.shadows.ShadowViewGroup.addView(ShadowViewGroup.java:32)
    at android.view.ViewGroup.addView(ViewGroup.java)
    at android.view.ViewGroup.addView(ViewGroup.java:3225)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:497)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
    at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
    at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
    at android.app.Activity.setContentView(Activity.java)
    at com.taskrabbit.droidrabbitstaging.TRRootDrawerActivity.onCreate(TRRootDrawerActivity.java:35)
    at com.taskrabbit.droidrabbitstaging.ui.routes.EmptyRouteActivity.onCreate(EmptyRouteActivity.java:34)
    at com.taskrabbit.droidrabbitstaging.ui.routes.EmptyRouteActivityTest.setUp(EmptyRouteActivityTest.java:62)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:241)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

我尝试将它们设置为硬编码值(例如400dp),这样可以解决测试中的问题。但是,我随后在我的手机上安装的应用程序中无法使宽度和高度等于match_parent。是否有任何方法可以设置Robolectric设备的宽度和高度?或者有没有人遇到过这个问题并提出了其他解决方法?

似乎与此问题有关:https://code.google.com/p/android/issues/detail?id=55611 注意,该问题的另一个副作用是Design View被破坏了。


如果您扩展DrawerLayout并确保MeasureSpecs被强制正确,会怎样呢?我也遇到了同样的问题,所以我会尝试这样做。 - joecks
3个回答

30
在做一些调查后,我找到了一个解决方案。看起来Robolectric在计算MeasureSpecs时出现了错误,导致了这个问题。在我的情况下,我可以通过扩展DrawerLayout并重写onMeasure()方法来解决这个问题。
public class CustomDrawerLayout extends DrawerLayout {

    public CustomDrawerLayout(Context context) {
        super(context);
    }

    public CustomDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(
                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

}

3
我刚刚发现了你的回答joecks... 我试图从一个drawerlayout视图中的片段启动一个意图,这让我很烦恼... 非常感谢你! - Evan R.
尽管Google声称在Android Support Library修订版19(2013年10月)中已经解决了这个问题,但这仍然是一个运行时问题。这个hack比我之前的hack要好得多。 - DataGraham

0

在您的安卓设备上运行程序即可。它可以完美地运行。我猜只是在Eclipse中出了一些问题。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接