왜 Onlayout과 Onsizechanged가 오리엔테이션 변경에서 두 번 전화를받는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com//questions/9696118

문제

나는 조경 변화로부터의 구성 변경을 취급 할 때, 조경 -> 초상화 또는 세로 -> 가로에서 오리엔테이션이 변경된 후에 Onlayout 및 Onsizechanged 을 즉각적으로 연속적으로 이라고 불렀다. ...에 또한, 첫 번째 onLayout / OnSizeChanged는 이전 차원 (회전 전)을 포함하고 있으며, 2 번째 onlayout / OnSizeChanged는 new (올바른) 차원을 포함합니다.

왜 누구든지 이유를 알고 있는지, 그리고 / 또는 어떻게 해결 방법을 알고 있습니까? 아마도 화면 크기 변경이 구성 변경 후에 상당히 일어난 것처럼 보이는 것처럼 보이는 것으로 보인다 - I.E.e.은 onConfigurationChanged가 호출 될 때 구성 변경 직후에 차원이 올바르지 않습니다.

여기에 코드의 디버그 출력은 초상화에서 가로까지 회전 한 후 OnLayout / OnsizeChanged 통화를 모두 보여줍니다 (장치는 540x960이므로 세로 폭이 540이면 가로 폭이 960이어야합니다).

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

또한 첫 번째 온스 티아 셰 콜드 oldwidth와 oldheight가 0이며, 우리가 뷰 계층 구조에 추가되었음을 나타내는 0입니다. 아직 exploy 조경을위한 치수!

여기에는이 동작을 보여주는 코드가 있습니다.

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

myHorizontAlsCrollView.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,%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));
    }
}
.

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> 
.
도움이 되었습니까?

해결책

나는 이것을 아주 오랫동안 자신을 궁금해하고있었습니다.

해답에 대해 대답 한 방식 - 대답이 믿는 것을 믿기 때문에, 그것은 (ko) try/catch 메소드에 requestLayout 또는 로깅 명령문을 추가하는 것입니다. 이렇게하면 재 방문 및 재구성 요청이 누구와의 try/catch,의 경우를 확인할 수 있습니다.

Android Works에서 누워있는 방식은 requestLayout가있는 더러운 레이아웃을 갖는 것으로보기를 표시하는 것입니다. 일부 간격에서 UI 스레드에서 항상 실행되는 안드로이드 루퍼는 미래의 일부 불확정 지점에서 더러운 것으로 표시된 트리에서 뷰를 재 시행하고 재발개합니다.

i onConfigurationChanged를 짐작하기 위해 Venture, 여러분의 requestLayout 호출을 가져오고 루퍼는 그 중간의 어딘가에있는 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
.

Android 문서는 측정 및 배치에 더 많은 정보가 있습니다. 그러나 위에서 설명한 세부 사항에는 슬프게도 짧습니다.

이벤트 처리 및 스레딩

뷰의 기본주기는 다음과 같습니다.

  1. 이벤트가 들어 있고 적절한보기에 전달됩니다. 이 뷰는 이벤트를 처리하고 모든 청취자에게 알립니다.
  2. 이벤트를 처리하는 과정에서 뷰의 경계를 변경해야 할 수 있으므로 requestlayout () 호출합니다.
  3. 마찬가지로 뷰의 모양을 변경 해야하는 과정에서 뷰가 무효화 () 호출 할 수 있습니다.
  4. requestLayout () 또는 무효화 ()가 호출 된 경우, 프레임 워크는 측정, 배치 및 그리기를 처리합니다. 적절한 나무.
  5. 참고 : 전체보기 트리는 단일 스레드입니다. 당신은 항상 일해야합니다 모든보기에서 모든 메소드를 호출 할 때 UI 스레드입니다. 네가하고 있다면 다른 스레드에서 작업하고 뷰 상태를 업데이트하고 싶습니다. 스레드, 핸들러를 사용해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top