| Author |
Message |
divestoclimb Developer

Joined: 11 May 2009 Posts: 33
|
Posted: Mon Sep 28, 2009 6:08 am Post subject: Custom View w/ EditTexts: state being overwritten |
|
|
I'm trying to figure out how to properly make a custom view consisting of a LinearLayout and some children, one of which is a EditText. To make this simple, I've pared down the code to the simplest possible case.
res/layout/bughunt.xml is a basic definition of a custom view; it's just a layout with a single EditText inside.
| XML: |
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<EditText
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="40sp"
android:gravity="center"
android:width="50sp"
android:singleLine="true"/>
</LinearLayout>
|
My custom view class:
| Java: |
public class BugHunt extends LinearLayout {
public BugHunt(Context context) {
super(context);
initLayout(context);
}
public BugHunt(Context context, AttributeSet attrs) {
super(context, attrs);
initLayout(context);
}
private void initLayout(Context context) {
LayoutInflater i = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
i.inflate(R.layout.bughunt, this);
}
}
|
Then I put two instances like the following in an Activity layout file:
| XML: |
<my.package.BugHunt
layout_width="wrap_content"
layout_height="wrap_content" />
|
The problem I'm having is when the EditTexts save state, they overwrite each other's state. To reproduce this, put two or more instances of BugHunt into an Activity, run it, and enter some (different) text into each EditText. Then, switch the screen orientation. After the layout is redrawn, all EditTexts will have the same text in them (the text from whichever EditText saved state last).
I can only guess that I'm not using the LayoutInflater properly. Any ideas? |
|
| Back to top |
|
 |
|
|
 |
divestoclimb Developer

Joined: 11 May 2009 Posts: 33
|
Posted: Mon Sep 28, 2009 3:19 pm Post subject: |
|
|
| I got a reply on android-developers that this is the result of having the same ID for each EditText. I'm devising a method to work around this and will post it here for everyone's benefit when I get it working. |
|
| Back to top |
|
 |
divestoclimb Developer

Joined: 11 May 2009 Posts: 33
|
Posted: Tue Sep 29, 2009 2:34 am Post subject: |
|
|
Here's the 90% solution.
First, I abstracted a bit of processing into a separate class called ViewId, which generates an ID unique within the passed View:
| Java: |
public class ViewId {
public static int generateUnique(View v) {
Random r = new Random();
int id;
do {
id = r.nextInt();
} while(v.findViewById(id) != null);
return id;
}
}
|
Then I made these changes in my example BugHunt class:
| Java: |
private void initLayout(Context context) {
LayoutInflater i = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
i.inflate(R.layout.bughunt, this);
mEditText = (EditText)findViewById(R.id.text1);
setEditTextId(ViewId.generateUnique(getRootView()));
}
protected void setEditTextId(int id) {
mEditText.setId(id);
}
|
This allows the EditText to always have a unique ID after the layout is inflated. This is only half the solution, though, because when the Activity is recreated the EditText will get assigned a different random ID. To handle that, I had to override the onSaveInstanceState and onRestoreInstanceState methods to save/restore the ID in a custom SavedState object (code borrowed heavily from TextView):
| Java: |
public static class SavedState extends BaseSavedState {
int textId;
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(textId);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
private SavedState(Parcel in) {
super(in);
textId = in.readInt();
}
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.textId = mEditText.getId();
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
setEditTextId(ss.textId);
}
|
The only thing not working here is that focus won't get restored to the EditText, which is weird because adb logcat usually shows that the Window fails to find the ID after it's already been set. I don't really care though, this is enough for me. Hopefully this helps somebody, and hopefully this sort of thing will be made easier in future revisions of the API. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
© 2007, Android Development Community
All rights reserved.
Powered by phpBB.
|