Android 为什么onLayout和onSizeChanged在方向更改时会被调用两次?

Android 为什么onLayout和onSizeChanged在方向更改时会被调用两次?,android,android-layout,android-orientation,android-configchanges,Android,Android Layout,Android Orientation,Android Configchanges,我注意到,当处理活动中的配置更改时,在方向更改后,onLayout和onSizeChanged会立即连续两次被调用,无论是从横向->纵向还是从纵向->横向。此外,第一个OnlyLayout/onSizeChanged包含旧尺寸(在旋转之前),而第二个OnlyLayout/onSizeChanged包含新的(正确的)尺寸 有人知道为什么,和/或如何解决这个问题吗?看起来屏幕大小可能在配置更改后很长一段时间内发生更改-即,当调用onConfigurationChanged时,配置更改后的尺寸不正确

我注意到,当处理活动中的配置更改时,在方向更改后,onLayout和onSizeChanged会立即连续两次被调用,无论是从横向->纵向还是从纵向->横向。此外,第一个OnlyLayout/onSizeChanged包含旧尺寸(在旋转之前),而第二个OnlyLayout/onSizeChanged包含新的(正确的)尺寸

有人知道为什么,和/或如何解决这个问题吗?看起来屏幕大小可能在配置更改后很长一段时间内发生更改-即,当调用
onConfigurationChanged
时,配置更改后的尺寸不正确

下面是代码的调试输出,显示了从纵向到横向旋转后的onLayout/onSizeChanged调用(请注意,设备为540x960,因此横向宽度应为960,而纵向宽度为540):

还要注意的是,第一个onSizeChanged oldwidth和oldheight为0,这表明我们刚刚添加到视图层次结构中,但横向尺寸错误

下面是说明这种行为的代码:

MyActivity.java MyHorizontalScrollView.java AndroidManifest.xml
我自己也一直在想这个问题很久了

我回答这个问题的方式——因为我相信答案是,这要看情况而定——是在
requestLayout
方法中添加
try/catch
或logging语句。这允许您查看何时提出重新测量和重新布置的请求,以及在
try/catch的情况下,
由谁提出

Android works中的布局方式是使用
requestLayout
将视图标记为具有脏布局。一个总是在UI线程上每隔一段时间运行的Android looper将重新测量并重新布局树中的视图,这些视图在将来的某个不确定点被标记为脏视图

<>我冒昧地猜测<代码> OnDealTeCase< <代码>,您得到了几个<代码>请求布局>代码>调用,而套接字正在调用它们中间的某个地方的代码> <代码> >

这就是日志记录对我来说的样子:

11-07 15:39:13.624: W/YARIAN(30006): requestLayout
11-07 15:39:13.632: W/YARIAN(30006): requestLayout
11-07 15:39:13.640: W/YARIAN(30006): requestLayout
11-07 15:39:13.647: W/YARIAN(30006): requestLayout
11-07 15:39:13.686: W/YARIAN(30006): requestLayout
11-07 15:39:13.718: W/YARIAN(30006): requestLayout
11-07 15:39:13.827: W/YARIAN(30006): requestLayout
11-07 15:39:14.108: W/YARIAN(30006): onLayout
11-07 15:39:14.155: W/YARIAN(30006): requestLayout
11-07 15:39:14.272: W/YARIAN(30006): onLayout
关于测量和布局,但遗憾的是,我在上面描述的细节方面做得不够

事件处理和线程

视图的基本循环如下所示:

  • 一个事件进入并被分派到相应的视图。视图处理事件并通知所有侦听器
  • 如果在处理事件的过程中,可能需要更改视图的边界,则视图将调用requestLayout()
  • 类似地,如果在处理事件的过程中可能需要更改视图的外观,则视图将调用invalidate()
  • 如果调用了requestLayout()或invalidate(),框架将负责测量、布局和绘制 视情况而定
  • 注意:整个视图树是单线程的。你必须一直在电视上 在任何视图上调用任何方法时的UI线程。如果你正在做 在其他线程上工作,并希望从该线程更新视图的状态 线程,您应该使用处理程序


    我不知道确切的答案,但它是否指向一个从旧方向退出的事件和另一个从新方向退出的事件?因此传递的数据集可能会向事件建议旧的和新的视口度量值感谢kishu27的建议-两组维度肯定是旧的然后是新的维度;但是第一个onSizeChanged(oldw,oldh)的最后两个参数是0,0,这表明我们刚刚添加到视图层次结构(使用错误的维度!)
    package com.example;
    
    import android.app.Activity;
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.FrameLayout;
    
    public class MyActivity extends Activity
    {
        private static String TAG = "RotateTest";
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            Log.d(TAG, "onConfigurationChanged: " + (newConfig.orientation == 1 ? "PORTRAIT" : "LANDSCAPE"));
            super.onConfigurationChanged(newConfig);
            _setView();
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            Log.d(TAG, "onCreate");
            super.onCreate(savedInstanceState);
            _setView();
        }
    
        private void _setView() {
            MyHorizontalScrollView scrollView = new MyHorizontalScrollView(this, null);
            setContentView(scrollView);
        }
    }
    
    package com.example;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.widget.HorizontalScrollView;
    
    public class MyHorizontalScrollView extends HorizontalScrollView {
    
        private static String TAG = "RotateTest";
    
        public MyHorizontalScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            Log.d(TAG, "onLayout:" + String.format("%s-%d,%d,%d,%d", changed, l, t, r, b));
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            Log.d(TAG, "onSizeChanged:" + String.format("%d,%d,%d,%d", w, h, oldw, oldh));
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example"
          android:versionCode="1"
          android:versionName="1.0"
            >
    
        <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="9"/>
    
        <application android:label="@string/app_name"
                >
            <activity android:name="MyActivity"
                      android:label="@string/app_name"
                      android:configChanges="orientation"
                    >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest> 
    
    11-07 15:39:13.624: W/YARIAN(30006): requestLayout
    11-07 15:39:13.632: W/YARIAN(30006): requestLayout
    11-07 15:39:13.640: W/YARIAN(30006): requestLayout
    11-07 15:39:13.647: W/YARIAN(30006): requestLayout
    11-07 15:39:13.686: W/YARIAN(30006): requestLayout
    11-07 15:39:13.718: W/YARIAN(30006): requestLayout
    11-07 15:39:13.827: W/YARIAN(30006): requestLayout
    11-07 15:39:14.108: W/YARIAN(30006): onLayout
    11-07 15:39:14.155: W/YARIAN(30006): requestLayout
    11-07 15:39:14.272: W/YARIAN(30006): onLayout