Skip to content

Commit 505bd0d

Browse files
Martin WallgrenJohan Redestig
authored andcommitted
onDetachedFromWindow is called before onAttachedToWindow
Multiple threads are adding messages about the current state of the views to the main looper. This can cause onDetachedFromWindow to be posted on the looper before onAttachedToWindow. This change will make sure to only dispatch onDetachedFromWindow if we have previously dispatched onAttachToWindow. Change-Id: Ibc7cbcafb098bc000d2ef5480d2110d3fff4d55a
1 parent 08d9d9a commit 505bd0d

File tree

6 files changed

+190
-2
lines changed

6 files changed

+190
-2
lines changed

core/java/android/view/ViewRoot.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ public final class ViewRoot extends Handler implements ViewParent,
176176
private final Surface mSurface = new Surface();
177177

178178
boolean mAdded;
179+
private boolean mAttached;
179180
boolean mAddedTouchMode;
180181

181182
/*package*/ int mAddNesting;
@@ -762,7 +763,10 @@ private void performTraversals() {
762763
attachInfo.mKeepScreenOn = false;
763764
viewVisibilityChanged = false;
764765
mLastConfiguration.setTo(host.getResources().getConfiguration());
765-
host.dispatchAttachedToWindow(attachInfo, 0);
766+
if (!mAttached) {
767+
host.dispatchAttachedToWindow(attachInfo, 0);
768+
mAttached = true;
769+
}
766770
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
767771

768772
} else {
@@ -1743,8 +1747,9 @@ public void recomputeViewAttributes(View child) {
17431747
void dispatchDetachedFromWindow() {
17441748
if (Config.LOGV) Log.v(TAG, "Detaching in " + this + " of " + mSurface);
17451749

1746-
if (mView != null) {
1750+
if (mView != null && mAttached) {
17471751
mView.dispatchDetachedFromWindow();
1752+
mAttached = false;
17481753
}
17491754

17501755
mView = null;

core/tests/coretests/AndroidManifest.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@
9696

9797
<application android:theme="@style/Theme">
9898
<uses-library android:name="android.test.runner" />
99+
<activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test">
100+
<intent-filter>
101+
<action android:name="android.intent.action.MAIN" />
102+
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
103+
</intent-filter>
104+
</activity>
99105
<activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser">
100106
<intent-filter>
101107
<action android:name="android.intent.action.MAIN"/>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:orientation="vertical"
5+
android:layout_width="fill_parent"
6+
android:layout_height="fill_parent">
7+
<android.view.ViewAttachView
8+
android:id="@+id/view_attach_view"
9+
android:layout_width="match_parent"
10+
android:layout_height="match_parent"
11+
android:keepScreenOn="true"/>
12+
</LinearLayout>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) 2011 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.view;
18+
19+
import android.content.pm.ActivityInfo;
20+
import android.os.SystemClock;
21+
import android.test.ActivityInstrumentationTestCase2;
22+
23+
public class ViewAttachTest extends
24+
ActivityInstrumentationTestCase2<ViewAttachTestActivity> {
25+
26+
public ViewAttachTest() {
27+
super(ViewAttachTestActivity.class);
28+
}
29+
30+
/**
31+
* Make sure that onAttachedToWindow and onDetachedToWindow is called in the
32+
* correct order The ViewAttachTestActivity contains a view that will throw
33+
* an RuntimeException if onDetachedToWindow and onAttachedToWindow is
34+
* called in the wrong order.
35+
*
36+
* 1. Initiate the activity 2. Perform a series of orientation changes to
37+
* the activity (this will force the View hierarchy to be rebuild,
38+
* generating onAttachedToWindow and onDetachedToWindow)
39+
*
40+
* Expected result: No RuntimeException is thrown from the TestView in
41+
* ViewFlipperTestActivity.
42+
*
43+
* @throws Throwable
44+
*/
45+
public void testAttached() throws Throwable {
46+
final ViewAttachTestActivity activity = getActivity();
47+
for (int i = 0; i < 20; i++) {
48+
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
49+
SystemClock.sleep(250);
50+
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
51+
SystemClock.sleep(250);
52+
}
53+
}
54+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (C) 2011 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.view;
18+
19+
import com.android.frameworks.coretests.R;
20+
21+
import android.app.Activity;
22+
import android.os.Bundle;
23+
24+
public class ViewAttachTestActivity extends Activity {
25+
public static final String TAG = "OnAttachedTest";
26+
@Override
27+
public void onCreate(Bundle savedInstanceState) {
28+
super.onCreate(savedInstanceState);
29+
setContentView(R.layout.attach_view_test);
30+
}
31+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (C) 2011 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.view;
18+
19+
import android.content.Context;
20+
import android.graphics.Canvas;
21+
import android.graphics.Color;
22+
import android.os.SystemClock;
23+
import android.util.AttributeSet;
24+
import android.util.Log;
25+
import android.view.View;
26+
27+
/**
28+
* A View that will throw a RuntimeException if onAttachedToWindow and
29+
* onDetachedFromWindow is called in the wrong order for ViewAttachTest
30+
*/
31+
public class ViewAttachView extends View {
32+
public static final String TAG = "OnAttachedTest";
33+
private boolean attached;
34+
35+
public ViewAttachView(Context context, AttributeSet attrs, int defStyle) {
36+
super(context, attrs, defStyle);
37+
init(attrs, defStyle);
38+
}
39+
40+
public ViewAttachView(Context context, AttributeSet attrs) {
41+
super(context, attrs);
42+
init(attrs, 0);
43+
}
44+
45+
public ViewAttachView(Context context) {
46+
super(context);
47+
init(null, 0);
48+
}
49+
50+
private void init(AttributeSet attrs, int defStyle) {
51+
SystemClock.sleep(2000);
52+
}
53+
54+
@Override
55+
protected void onAttachedToWindow() {
56+
Log.d(TAG, "onAttachedToWindow");
57+
super.onAttachedToWindow();
58+
if (attached) {
59+
throw new RuntimeException("OnAttachedToWindow called more than once in a row");
60+
}
61+
attached = true;
62+
}
63+
64+
@Override
65+
protected void onDetachedFromWindow() {
66+
Log.d(TAG, "onDetachedFromWindow");
67+
super.onDetachedFromWindow();
68+
if (!attached) {
69+
throw new RuntimeException(
70+
"onDetachedFromWindowcalled without prior call to OnAttachedToWindow");
71+
}
72+
attached = false;
73+
}
74+
75+
@Override
76+
protected void onDraw(Canvas canvas) {
77+
super.onDraw(canvas);
78+
canvas.drawColor(Color.BLUE);
79+
}
80+
}

0 commit comments

Comments
 (0)