| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.example.android.requestduringlayout; |
| |
| import com.android.requestduringlayout.R; |
| |
| import android.app.Activity; |
| import android.content.Context; |
| import android.os.Bundle; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.widget.Button; |
| import android.widget.LinearLayout; |
| |
| /** |
| * This example shows what horrible things can result from calling requestLayout() during |
| * a layout pass. DON'T DO THIS. |
| * |
| * Watch the associated video for this demo on the DevBytes channel of developer.android.com |
| * or on YouTube at https://www.youtube.com/watch?v=HbAeTGoKG6k. |
| */ |
| public class RequestDuringLayout extends Activity { |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.activity_request_during_layout); |
| |
| final MyLayout myLayout = (MyLayout) findViewById(R.id.container); |
| Button addViewButton = (Button) findViewById(R.id.addView); |
| Button removeViewButton = (Button) findViewById(R.id.removeView); |
| Button forceLayoutButton = (Button) findViewById(R.id.forceLayout); |
| |
| addViewButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| myLayout.mAddRequestPending = true; |
| myLayout.requestLayout(); |
| } |
| }); |
| |
| removeViewButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| myLayout.mRemoveRequestPending = true; |
| myLayout.requestLayout(); |
| } |
| }); |
| |
| forceLayoutButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| myLayout.requestLayout(); |
| } |
| }); |
| |
| } |
| |
| /** |
| * Custom layout to enable the convoluted way of requesting-during-layout that we're |
| * trying to show here. Yes, it's a hack. But it's a case that many apps hit (in much more |
| * complicated and less demoable ways), so it's interesting to at least understand the |
| * artifacts that come from this sequence of events. |
| */ |
| static class MyLayout extends LinearLayout { |
| |
| int numButtons = 0; |
| boolean mAddRequestPending = false; |
| boolean mRemoveRequestPending = false; |
| |
| public MyLayout(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| } |
| |
| public MyLayout(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public MyLayout(Context context) { |
| super(context); |
| } |
| |
| @Override |
| protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| super.onLayout(changed, l, t, r, b); |
| // Here is the root of the problem: we are adding/removing views during layout. This |
| // means that this view and its container will be put into an uncertain state that |
| // can be difficult to discover and recover from. |
| // Better approach: just add/remove at a time when layout is not running, certainly not |
| // in the middle of onLayout(), or other layout-associated logic. |
| if (mRemoveRequestPending) { |
| removeButton(); |
| mRemoveRequestPending = false; |
| } |
| if (mAddRequestPending) { |
| addButton(); |
| mAddRequestPending = false; |
| } |
| } |
| |
| private void removeButton() { |
| if (getChildCount() > 1) { |
| removeViewAt(1); |
| } |
| } |
| |
| private void addButton() { |
| Button button = new Button(getContext()); |
| button.setLayoutParams(new LayoutParams( |
| LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); |
| button.setText("Button " + (numButtons++)); |
| addView(button); |
| } |
| |
| } |
| |
| } |