1

Cross posting from Android Google group

I ran into this issue earlier today: https://code.google.com/p/android/issues/detail?id=55106

The problem is:

  • LinearLayout has children
  • every child is inflated from the same XML layout file
  • a child has nested element with some ID.
    • The ID is used to call findViewById(ID) to set some value
  • Everything is displayed properly on startup, but after orientation change every child of LinearLayout displays the value of the last data item
  • As soon as ID is removed from the child XML layout file, everything starts working properly

The bug has the sample project attached that demonstrates the problem.

Just wanted to ask if somebody has experienced the same issue and knows a workaround?

Thank you in advance.


EDIT:

The situation with LinearLayout is pretty flaky. I finally made the project work - see the second attached project at https://code.google.com/p/android/issues/detail?id=55106

If you go to item_main.xml and change android:textIsSelectable from false to true, the bug shows up. Keep android:textIsSelectable="true", but remove android:id="@+id/text" - the bug disappears again

The main reason I was experimenting with this LinearLayout is because I wanted to follow thy layout animation sample. http://developer.android.com/training/animation/layout.html

But it seems the situation is so unstable with LinearLayout and orientation change that I need to go back to the working ListView+Adapter approach and figure out how to do similar layout animations when adding items to the adapter and revalidating the list.

Y2i
  • 3,748
  • 2
  • 28
  • 32
  • See http://stackoverflow.com/questions/14263665/why-does-a-progressbars-id-need-to-be-unique/14265726#14265726 . Your problem is most likely related to saving and restoring the activity's state. Consider implementing onSaveInstanceState() and onRestoreInstanceState() – frozenkoi May 10 '13 at 19:18
  • It does not seem so. The larger project I'm working on implements onSaveInstanceState(). Based on my findings with the fragment it looks like a framework bug. https://code.google.com/p/android/issues/detail?id=55106 In addition, I also found that if I take activity-based Layout Animation sample from Google and change TextView's ID from @android:id/text1 to @+id/text1, their sample stops working as well. LinearLayout, textIsSelectable and id are really flaky in combination. – Y2i May 10 '13 at 22:13

3 Answers3

2

Another workaround is removing all views from your LinearLayout in onSaveInstanceState method.

@Override
protected void onSaveInstanceState(Bundle outState) {
    LinearLayout linearLayout = (LinearLayout) findViewById(R.id.yourLinearLayoutId);
    linearLayout.removeAllViews();
    super.onSaveInstanceState(outState);
}
  • This does seem to be the problem, but unfortunately clearing the views just before the state is saved off didn't work for me (not sure why!?). I did take a hint from this though and just build my linear layout children in the onViewStateRestored() method, after calling super. This works for me anyway, not the best solution. This issue only happens with Switch components in my case, doesn't happen to anything else in my inflated views. Curious. – reactive-core Sep 01 '14 at 06:05
0

Do you have any particular reason why you are inflating 50 children layouts and then inserting them into a ScrollView instead of using an AdapterView?

It seems to me like you should probably be using ListView with some sort of Adapter that will handle the row inflating and data binding for you, which will result in not only improved efficiency and performance but will let you avoid this "bug" which you are encountering.

Any time you are inflating Views within a loop it should be a strong hint that you ought to re-consider your approach and start using an AdapterView of some sort (ListView, Gallery etc...)

FoamyGuy
  • 46,603
  • 18
  • 125
  • 156
  • 50 children is just a sample to see scrolling. In the real app it is typically 4-5 views, but larger, so the scrolling can be seen without adding too many views. The main reason for using LienarLayout is to follow this framework sample: http://developer.android.com/training/animation/layout.html – Y2i May 09 '13 at 21:38
0

When you add a number of TextViews and re-use the same id for them (android:id="@+id/text") my best guess would be that you're stumbling on unexpected behavior (at best) once you invoke the findViewByID method. To do what you apparently want to do (use a list of TextViews you could be doing something like what was proposed here, i.e. create an array of TextViews, instance them and keep them for internal reference.

What you found isn't actually a bug, it's behaving like it should: all the TextViews have the same id, so all will change at the same time.

I looked up the actual reference in the documentation (emphasis mine):

An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree you are searching (which may often be the entire tree, so it's best to be completely unique when possible).

Community
  • 1
  • 1
DigCamara
  • 5,540
  • 4
  • 36
  • 47
  • I would not calling findViewById() from the container, that would be a problem, bug calling it from the child view itself is not a problem because the search is limited to the child. Having a ListView + Adapter would have the same problem if calling findViewById() from the ListView container itself. Regarding the same id on TextView: apparently it is not a problem when instantiating LinearLayout for the frist time. It becomes a problem after re-creating the same view after the orientation change within the fragment. I still think it is a framework bug. – Y2i May 09 '13 at 22:00
  • Think about it. You are adding a number of siblings to a LinearLayout. They are all named the same and resolved, for instance to the value 123. Which one **should** the framework be returning when you ask it for findViewById(123)? The first? The second? The last? Indeed, the framework tells you a number of times that the identifier does not have to be unique (for instance http://developer.android.com/reference/android/view/View.html#setId(int)) – DigCamara May 09 '13 at 22:10
  • (By the way: could you rephrase what you wanted to say before "It becomes a problem..." I honestly couldn't understand what you were trying to say.) – DigCamara May 09 '13 at 22:10
  • It is well common technique to inflate children from the same XML layout. It is also common to for these children to have IDs defined. They will be the same IDs. ListView + Adapter use this technique. findViewById() is only a problem if called on or above the container in the view hierarchy. findViewById() is not a problem if called on the child itself. – Y2i May 09 '13 at 22:23
  • Look: nobody says the technique is wrong. It's also not wrong for them to have IDs defined. The documentation actually says so: the id's **should** be different, they **must** not be. The problem is only that you're expecting the function to do something it isn't designed to do (sort out which one of the existing id's you want it to access even though they are the same) – DigCamara May 09 '13 at 22:33
  • "The IDs should be unique within the part of the tree you are searching." I've never searched from the parent scope, only from the child scope, searching is not a problem at all. – Y2i May 09 '13 at 22:39