开发者

Checkboxes all showing the same text after switching orientations

Edit: See the accepted answer. Lesson: Sometimes views will save and restore their state automatically. This happens AFTER onCreate. This can cause the overwriting of stuff you did in onCreate. If you don't have unique ids, all views of a certain kind (in my case textboxes) can be overwritten with the same saved state. (ps: thanks for your help everyone!)

So, I have a simple linear layout and I want to add some views that have checkboxes with images. Everything works fine until I switch the orientation of my android phone. When I do it goes back through the onCreate but this time the checkboxes all end up with the same text. Weirdly, the images appear fine.

My question is: why is it doing this and how can I make it appear like the first time everytime?

In case that makes no sense here's an example: (Edit: It turns out it always shows the last element's text)

What I see at first

[] a *a'开发者_运维百科s image*
[] b *b's image*
[] c *c's image*
[] d *d's image*

Then, after rotating my phone, it redraws

[] d *a's image*
[] d *b's image*
[] d *c's image*
[] d *d's image*

My original code is pretty complex, but i constructed the following that demonstrates the problem.

Main.java:

public class Main extends Activity {

ArrayList<AnswerView> answers = new ArrayList<AnswerView>();

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    TextView title = (TextView)findViewById(R.id.questionText);
    title.setText("This is a test");
    HashMap<String, Drawable> answerInfo = new HashMap<String, Drawable>();
    Resources res = getResources();
    answerInfo.put("a", res.getDrawable(R.drawable.flower_orange));
    answerInfo.put("b", res.getDrawable(R.drawable.flower_white));
    answerInfo.put("c", res.getDrawable(R.drawable.leaf));
    answerInfo.put("d", res.getDrawable(R.drawable.flower_yellow));
    setBoxes(answerInfo);
}

private void setBoxes(HashMap<String, Drawable> answerInfo) {
    LinearLayout answerList = (LinearLayout)findViewById(R.id.answerlist);
    AnswerView cb = null;

    //Remove all existing answer views
    answerList.removeAllViews();
    answers.clear();

    //For each possible answer create a answer views
    for (String s : answerInfo.keySet()) {
        cb = new AnswerView(this, s, answerInfo.get(s));
        answers.add(cb);
        String text = cb.getText();
        answerList.addView(cb);
    }
}
}

AnswerView.java

 public class AnswerView extends RelativeLayout  {

private CheckBox m_checkbox;
private ImageView m_image;
//private Context m_context;

public AnswerView(Context context, String answer, Drawable d) {
    super(context);
    LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.image_checkbox, this, true);
    m_checkbox = (CheckBox) view.findViewById(R.id.image_checkbox_cb);
    m_image = (ImageView) view.findViewById(R.id.image_checkbox_img);
    //m_context = context;
    m_checkbox.setText(answer);
    m_image.setImageDrawable(d);
    m_image.setVisibility(VISIBLE);

}

public void setChecked(boolean checked) {
    m_checkbox.setChecked(checked);
}

public boolean isChecked() {
    return m_checkbox.isChecked();
}

public String getText() {
    return m_checkbox.getText().toString();
}

}

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
        android:layout_height="wrap_content">
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical" 
  android:padding="5dip">

  <TextView android:orientation="vertical" 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/questionText"
    android:textSize="18sp"/>

  <LinearLayout android:orientation="vertical" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/answerlist"/>
  <LinearLayout android:orientation="horizontal" 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center">
    <Button  
    android:layout_width="200dip" 
    android:layout_height="wrap_content" 
    android:text="Enter"
    android:id="@+id/buttonAnswerEnter"/>
    />
    </LinearLayout>

</LinearLayout>
</ScrollView>

image_checkbox.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="horizontal">
  <CheckBox
   android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/image_checkbox_cb"></CheckBox>
  <ImageView
  android:id="@+id/image_checkbox_img"
  android:layout_width="100dip" 
  android:layout_height="100dip" 
  android:visibility="gone"></ImageView>
    </LinearLayout>


Does setting a unique ID for each AnswerView solve your issue? You could achieve that as follows:

private void setBoxes(HashMap<String, Drawable> answerInfo) {
    LinearLayout answerList = (LinearLayout)findViewById(R.id.answerlist);
    AnswerView cb = null;

    //Remove all existing answer views
    answerList.removeAllViews();
    answers.clear();

    //For each possible answer create a answer views
    // BEGIN modified code
    int counter = 0;
    // END modified code
    for (String s : answerInfo.keySet()) {
        cb = new AnswerView(this, s, answerInfo.get(s));
        // BEGIN modified code
        cb.setId(counter);
        counter++;
        // END modified code
        answers.add(cb);
        String text = cb.getText();
        answerList.addView(cb);
    }
}


Implement

onSaveInstanceState ()
onRestoreInstanceState ()

in your custom layout AnswerView.


Try as I might, I'm unable to come up with reasoning for why this is occurring (and I would happily upvote anyone who can explain it), but here is a solution. For some reason, Android isn't happy with you adjusting the XML inflated layout so close to its actual inflation in setContentView(). The solution is to do the dynamic portion of the layout process either in onPostCreate() or onResume(), depending on your Activity needs.

I would recommend onResume() if you can afford it, since onPostCreate() is not typically suggested for override...however onResume() may be called to often and may mess up your layout. Here is your example modified to use onPostCreate() instead.

public class Main extends Activity {

    ArrayList<AnswerView> answers = new ArrayList<AnswerView>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView title = (TextView)findViewById(R.id.questionText);
        title.setText("This is a test");
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        HashMap<String, Drawable> answerInfo = new HashMap<String, Drawable>();
        Resources res = getResources();
        answerInfo.put("a", res.getDrawable(R.drawable.flower_orange));
        answerInfo.put("b", res.getDrawable(R.drawable.flower_white));
        answerInfo.put("c", res.getDrawable(R.drawable.leaf));
        answerInfo.put("d", res.getDrawable(R.drawable.flower_yellow));
        setBoxes(answerInfo);
    }

    private void setBoxes(HashMap<String, Drawable> answerInfo) {
        LinearLayout answerList = (LinearLayout)findViewById(R.id.answerlist);
        AnswerView cb = null;

        //Remove all existing answer views
        answerList.removeAllViews();
        answers.clear();

        //For each possible answer create a answer views
        for (String s : answerInfo.keySet()) {
            cb = new AnswerView(this, s, answerInfo.get(s));
            answers.add(cb);
            String text = cb.getText();
            answerList.addView(cb);
        }
    }
}

Two other things I noticed which may not affect you, but I figured I'd mention:

  1. If you want your items to always return in the same order, HashMap.keySet() is a bad choice. This method returns these values in different orders on different implementations. I would recommend a LinkedHashMap or a List if you need the order to always be the same.
  2. At least in this example, it doesn't make sense to clear your collections before setting them again...since this is only done when the Activity is reconstructed anyway. In the larger implementation, however, perhaps this has a larger purpose.

Hope that Helps! Feel free to ignore anything that wasn't useful :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜