3

I had asked one question about this error before (Android StackOverflowError in ViewGroup.resetResolvedTextDirection), however now I managed to reproduce the error in the emulator and narrowed down the specific place where this problem occurs.

When I'm starting my activity, I have an AsyncTask, which pulls the necessary data from my server and creates all views. Inside the run() method of the AsyncTask, I'm creating a custom view (and adding it to the main view of the activity - but that's not important now):

ListingView listing = new ListingView(MainActivity.this);

ListingView is my custom view class, which extends from LinearLayout. In the constructor of this custom view, I have this code:

public ListingView(Context context)
{
    this.context = context;
    ...

    LayoutInflater infl = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View top = infl.inflate(R.layout.listing, this, true);
    this.addView(top);
    ...

    LinearLayout lst = (LinearLayout)this.findViewById(R.id.LayoutListingTop);
    tblVenues = new ListView(context);
    tblVenues.setVisibility(VISIBLE);
    tblVenues.setItemsCanFocus(true);
    tblVenues.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            if(venueListener != null && venues.size() > 0) { venueListener.selected(venues.get(position)); }
        }
    });
    LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
    lst.addView(tblVenues, lp);    //this line causes the problem

    ...
}

In this custom view class, tblVenues is declared as

private ListView tblVenues;

And the XML that's being loaded is this:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:id="@+id/LayoutListingTop"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:background="@color/white">
    <ImageView android:id="@+id/ImageView01"
               android:layout_width="170dp"
               android:layout_height="62dp"
               android:src="@drawable/ookl_logo"
               android:layout_gravity="left"
               android:adjustViewBounds="false"
               android:scaleType="fitXY">
    </ImageView>

    <TextView android:layout_height="wrap_content"
              android:layout_width="fill_parent"
              android:layout_marginBottom="5px"
              android:gravity="center"
              android:textColor="@color/black"
              android:text="@string/love_culture"
              android:id="@+id/TextView01"
              android:textSize="28dip">
    </TextView>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="horizontal"
                  android:id="@+id/ButtonBar"
                  android:layout_width="fill_parent"
                  android:layout_height="wrap_content"
                  android:background="@drawable/buttonbar"
                  android:paddingLeft="10px"
                  android:paddingRight="10px"
                  android:paddingTop="5px"
                  android:paddingBottom="5px">

        <Button android:id="@+id/BtnListVenues"
                     android:layout_width="wrap_content"
                     android:layout_height="45dip"
                     android:background="@null"
                     android:text="@string/button_venues"
                     android:drawableTop="@drawable/icon_venues_on"
                     android:textColor="@color/venue_blue"
                     android:layout_marginRight="10px"
                     android:textSize="9dip">
        </Button>

        <Button android:id="@+id/BtnListEvents"
                     android:layout_width="wrap_content"
                     android:layout_height="45dip"
                     android:background="@null"
                     android:text="@string/button_events"
                     android:drawableTop="@drawable/icon_events_off"
                     android:textColor="@color/white"
                     android:layout_marginRight="10px"
                     android:textSize="9dip">
        </Button>

        <Button android:id="@+id/BtnListTrails"
                     android:layout_width="wrap_content"
                     android:layout_height="45dip"
                     android:background="@null"
                     android:text="@string/button_trails"
                     android:drawableTop="@drawable/icon_trails_off"
                     android:textColor="@color/white"
                     android:layout_marginRight="10px"
                     android:textSize="9dip">
        </Button>

        <Button android:id="@+id/BtnListObjects"
                     android:layout_width="wrap_content"
                     android:layout_height="45dip"
                     android:background="@null"
                     android:text="@string/button_objects"
                     android:drawableTop="@drawable/icon_objects_off"
                     android:textColor="@color/white"
                     android:layout_marginRight="10px"
                     android:textSize="9dip">
        </Button>

        <TextView android:id="@+id/TxtLabelDistance"
                  android:layout_width="fill_parent"
                  android:text="@string/label_distance"
                  android:layout_height="wrap_content"
                  android:gravity="right|bottom"
                  android:layout_alignParentBottom="true"
                  android:textColor="@color/white"
                  android:layout_marginTop="-17px"
                  android:textSize="9dip">
        </TextView>
    </LinearLayout>


</LinearLayout>

This all works perfectly fine on Android form 1.6 up to 3.x, however on Ice Cream Sandwich (4.0) line

lst.addView(tblVenues, lp);

results in StackOverflowError:

java.lang.StackOverflowError
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
at android.view.ViewGroup.resetResolvedTextDirection(ViewGroup.java:5131)
... this line repeats about 200 times or so ...

There's nothing else useful in the LogCat. The whole ListingView is not even added to the main activity view yet, because the error is thrown essentially from its constructor.

I'm a total loss as to what may be the problem. Any help will be greatly appreciated.

Community
  • 1
  • 1
Aleks G
  • 56,435
  • 29
  • 168
  • 265

3 Answers3

5

[Old question, but I wasn't pleased with the answer, so adding my notes in hope that they're helpful for someone else.]

Aleks -- I agree with the core issue being an Android bug, but tracing into the code (I encountered a similar issue recently) I believe the issue can be prevented by inflating with the attachToRoot parameter set to false. This is because with attacheToRoot==true, the returned view is the 'root' parameter you passed in. In your case that is 'this', which then add a child of the current view (you're adding the object as a child of itself). This seems to confuse android (it really should check for instance equality).

http://developer.android.com/reference/android/view/LayoutInflater.html#inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean)

"[Returns] The root View of the inflated hierarchy. If root was supplied and attachToRoot is true, this is root; otherwise it is the root of the inflated XML file."

Making this change resolved the issue in my case.

DSK
  • 558
  • 4
  • 8
  • Interesting... Yes, this question is old - and I did resolve the issue at the time (apparently). However just now I received another report of the same issue - specifically on Samsung Galaxy 4 device. Strangely enough, it doesn't occur on other devices with the same version of android, therefore this must be a bug in Samsung's implementation. Unfortunately, I don't have SG4 myself, so it would be quite difficult to debug. I'll give your idea a try. – Aleks G Oct 27 '13 at 07:39
3

Update: This is actually a bad advice, that I learned using the API through the years. See top voted answer. You must add a parent view in, even if it's hard to obtain. I believe that's because the layout_ parameters in your root element from the inflated XML depend on the parent layout. For example layout_below (or something like this) is available if your element is a child of a RelativeLayout. At least I got related problems when I passed null in.

I was debugging Android itself, because I made the same mistake, and I found the real reason. The real problem lies within these lines:

View top = infl.inflate(R.layout.listing, this, true);
this.addView(top);

As you can see, you pass this as the second parameter of inflate, that already adds the inflated view to this, so when you do this.addView(top), it gets added one more time. You have two options to correct a mistake like this: delete the line this.addView(top), or replace this with null. I haven't tried the second one, but it should work as well, and is probably a better solution, if you want to manipulate the views before adding to the parent after inflation.

The attachToRoot parameter, that BigDSK mentioned might suffice, but I find that passing null, and addViewing after that, or omitting the addView is a more bulletproof solution (IMHO), so I thought I would share.

Tamás Barta
  • 1,617
  • 1
  • 19
  • 23
  • 1
    Instead of replacing `this` with `null`, you can use `infl.inflate(R.layout.listing, this, false)` and keep the `this.addView(top)` line. – lucidbrot Jan 16 '19 at 12:23
  • lucidbrot, Yeah, I never pass `null` any more. This is actually a bad advice. I had trouble from passing in null. Thanks for the comment, I forgot I wrote this, now I'll update. – Tamás Barta Jan 16 '19 at 22:33
2

After banging my head against the wall for quite some time and trying all sorts of different approaches, I believe, this really is a bug in an android, which is exhibited when a View's visibility is explicitly set to VISIBLE but the view itself and the view's parent is not added to the main view.

I finally got around it by adding the ListView to XML and moving the code setVisibility(View.VISIBLE) to after the entire view is added to the main view (i.e. parent hierarchy can be traced from each child all the way to the end).

At least I'm not getting this error any more.

Aleks G
  • 56,435
  • 29
  • 168
  • 265