I\'m trying to write a custom compound view composed by a TextView
and an EditText
, _compound_view.xml_:
In case you have more complex compound view with many child view, you can consider overriding the dispatchSaveInstanceState
of your most outer ViewGroup
class and don't call the super implementation.
Like this:
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
//If you don't call super.dispatchRestoreInstanceState(container) here,
//no child view gets its state saved
}
I use this, because in my case I have hierarchy of many different compound views that have common super class in which I did this override. (I kept forgetting to set the SaveEnabled attribute to false for new layouts.) However there are many caveats, for example you need to manually save focused view and then request its focus, so your app doesn't behave oddly when screen is rotated.
EDIT:
If you actually need to save state of your compound view, overriding dispatchSaveInstanceState
with an empty body will cause onSave/RestoreInstanceState
not being called. If you want to use them and still not save state of any of the child views, you need to call super.dispatchFreezeSelfOnly(container)
in your override.
More on this here: http://charlesharley.com/2012/programming/views-saving-instance-state-in-android
Take a look at my comment in your question and also make sure that you're getting correctly the references to your views.
I'm using your code like this:
CompoundView cv1 = (CompoundView) findViewById(R.id.compoundview1);
TextView tv1 = (TextView) cv1.findViewById(R.id.textEdit);
CompoundView cv2 = (CompoundView) findViewById(R.id.compoundview2);
TextView tv2 = (TextView) cv2.findViewById(R.id.textEdit);
You need to disable SaveEnabled property of EditText using android:saveEnabled="false"
In your custom view, you are inflating layout from XML which has ID defined. Android OS has default functionality to save and restore the state of the view if the view has ID defined.
It means that it will save the text of the EditText when Activity gets paused and restore automatically when Activity gets restored. In your case, you are using this custom view multiple times and that is inflating the same layout so your all EditText have the same ID. Now when Activity will get pause Android will retrieve the value of the EditText and will save against their ID but as you have the same ID for each EditText, values will get override and so it will restore same value in all your EditText.
The issue is happening because of the id
field on compound_view.xml
From your code, I just noticed that you inflated compound_view
layout file in CompoundView
class.
As soon as you create compound_view.xml
and put android:id="@+id/textLabel"
and android:id="@+id/textEdit"
id in your layout xml
file, android studio automatically create those id
s into int
values in R
class for single time.
So, when you put CompoundView
twice time in your activity_main.xml
layout file, you just creating two instance of CompoundView
but, both instances textEdit
and textLabel
have only 1 address location for each one. So, they are pointing to same address locations which are declared in R
class.
That's why, whenever you change textEdit
or textLabel
text programatically, they also change other textEdit
or textLabel
which are presented in both of your CompoundView
I got the same annoying problem and solved it with another solution than the ones suggested. When the custom view is inflated, I don't find them with IDs or tags, I get them using the getChildAt
method. I did not have to save the instance state.
Here is an example:
Custom XML to inflate (custom_view.xml):
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"/>
</merge>
You then just get the views this way during the view initialization:
private void initView(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_view, this, true);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER);
TextView mTitleTV = (TextView) getChildAt(0);
EditText mContentET = (EditText) getChildAt(1);
}
IMPORTANT: you must remove all IDs from the XML
I'll start off by saying that I haven't confirmed this... but I experienced the same issues when using a compound view, similar to what you were doing.
I think the root of the problem is how Android automatically saves the state of EditText
controls, and I think it saves it by "id". So if you have multiple controls in your xml with same "id", then when it saves state, and then restores state, all controls with the same id get the same value. You can try this by adding 2 EditText
contols to you normal xml and give them the same android:id
value and see if they end up getting the same value.
In your case, you can try to NOT use ids in the compound view and rather find the elements another way, either by tag (View.findViewWithTag
), or by name, and see if that makes a difference.
In my case, I solved the problem by doing the latter.