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

前端之家收集整理的这篇文章主要介绍了android – 为什么onLayout和onSizeChanged在方向更改时被调用两次?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我注意到,在从“活动”处理配置更改时,onLayout和onSizeChanged在方向更改后立即连续被调用两次,无论是从横向纵向还是纵向 – 横向.此外,第一个onLayout / onSizeChanged包含旧的维度(在旋转之前),而第二个onLayout / onSizeChanged包含新的(正确的)维.

有谁知道为什么,和/或如何解决这个问题?看起来,在配置更改之后,屏幕尺寸的变化可能会发生很多时候 – 即在调用onConfigurationChanged时配置更改后,尺寸是否不正确?

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

03-13 17:36:21.140: DEBUG/RotateTest(27765): onConfigurationChanged: LANDSCAPE
03-13 17:36:21.169: DEBUG/RotateTest(27765): onSizeChanged:540,884,0
03-13 17:36:21.189: DEBUG/RotateTest(27765): onLayout:true-0,540,884
03-13 17:36:21.239: DEBUG/RotateTest(27765): onSizeChanged:960,464,884
03-13 17:36:21.259: DEBUG/RotateTest(27765): onLayout:true-0,960,464

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

这里是说明这个行为的代码

MyActivity.java

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);
    }
}

MyHorizo​​ntalScrollView.java

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",changed,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,w,oldh));
    }
}

AndroidManifest.xml中

<?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>

解决方法

我一直在想这个很长时间.

我回答这个问题的方式 – 因为我相信答案是,这取决于 – 通过在requestLayout方法添加一个try / catch或logging语句.这样,您可以查看何时进行重新测量和重新布置的请求,以及在尝试/捕获的情况下由谁执行.

Android中的布局方式是将您的视图标记为具有requestLayout的脏布局.总是在一段时间内在UI线程上运行的Android玩家将会在未来的某个不确定点重新设计和重新布置树中已经被标记为脏的视图.

我冒昧地猜测,onConfigurationChanged,你正在得到几个requestLayout调用,而looper正在调用onMeasure在其中的某个地方.

这就是我的日志记录:

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

The Android documentation has more information在测量和铺设时,可悲的是我上面描述的细节很短.

Event Handling and Threading

The basic cycle of a view is as follows:

  1. An event comes in and is dispatched to the appropriate view. The view handles the event and notifies any listeners.
  2. If in the course of processing the event,the view’s bounds may need to be changed,the view will call requestLayout().
  3. Similarly,if in the course of processing the event the view’s appearance may need to be changed,the view will call invalidate().
  4. If either requestLayout() or invalidate() were called,the framework will take care of measuring,laying out,and drawing the
    tree as appropriate.

Note: The entire view tree is single threaded. You must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread,you should use a Handler.

原文链接:https://www.f2er.com/android/311219.html

猜你在找的Android相关文章