question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

StackOverflowError when using touchExpansion

See original GitHub issue

Issues and Steps to Reproduce

I need to add a recyclerView in the toolbar of my activity, and I cannot call setContentView() with the LithoView. Currently, I’m trying to add the generated LithoView as a sub child to an existing LinearLayout. However, this sends the renderer into an infinite number of recursive calls and overflows the stack.

Expected Behavior

I expect the LinearLayout to add the LithoView as a child.

Link to Code

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        LinearLayout layout = toolbar.findViewById(R.id.tagLinearLayout);
        final ComponentContext context = new ComponentContext(this);
        RecyclerBinder binder = new RecyclerBinder(context, new LinearLayoutInfo(this,
            LinearLayout.HORIZONTAL, true));
        final Component component = Recycler.create(context)
                .binder(binder)
                .build();
        layout.addView(LithoView.create(context, component));
    }

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:11 (11 by maintainers)

github_iconTop GitHub Comments

4reactions
yuntaocommented, Aug 3, 2018

I work with @vinc3m1 and did some investigation into this issue.

This touch expansion related StackOverflowError (SOE) can be reproduced at both Litho layer and plain Android view layer. When touch expansion is set on any root Litho component, this logic propagates down to Android view layer and triggers a programmatically possible infinite loop condition in TouchDelegates and causes the SOE.

At Litho layer, the SOE can be triggered by setting touchExpansionDip and clickHandler on any root component. For example, both layout specs below produce the SOE when set as the root component to a LithoView:

@LayoutSpec
public class ColumnItemSpec {
  @OnCreateLayout
  static Component onCreateLayout(ComponentContext c) {
    return Column.create(c)
        .touchExpansionDip(ALL, 24)
        .clickHandler(ColumnItem.onClick(c))
        .build();
  }
  @OnEvent(ClickEvent.class)
  static void onClick(ComponentContext c, @FromEvent View view) {
  }
}
@LayoutSpec
public class TextItemSpec {
  @OnCreateLayout
  static Component onCreateLayout(ComponentContext c) {
    return Text.create(c)
        .text("Hello world")
        .touchExpansionDip(ALL, 24)
        .clickHandler(TextItem.onClick(c))
        .build();
  }
  @OnEvent(ClickEvent.class)
  static void onClick(ComponentContext c, @FromEvent View view) {
  }
}

At plain Android view layer, touch expansion is achieved by using a TouchDelegate in between a parent view group and a child view. It is programmatically possible to set a view’s TouchDelegate to delegate to itself, as seen below. This causes an infinite loop of forwarding touch event to the view itself and thus the SOE.

View anyView = findViewById(R.id.any_view);
anyView.post(new Runnable() {
    @Override
    public void run() {
        Rect expandRect = new Rect();
        anyView.getHitRect(expandRect);
        expandRect.left -= 100;
        expandRect.top -= 100;
        expandRect.right += 100;
        expandRect.bottom += 100;
        anyView.setTouchDelegate(new TouchDelegate(expandRect, anyView));
        // Correct way is to set touch expansion on containing child view:
        // anyView.setTouchDelegate(new TouchDelegate(expandRect, childView));
    }
});

Suggestions on what could be done as fixes:

  1. Update Litho docs on touch expansion to indicate that touch expansion should not be set on the root component and will not work. If touch expansion is desired on the root LithoView, then android.view.TouchDelegate should be used instead and the parent view group is also needed.

  2. Apply fix to ComponentHost class where we handle touch expansion to skip when the touch expansion is being set on a LithoView itself:

void maybeRegisterTouchExpansion(int index, MountItem mountItem) {  
    if (this == MountItem.getContent()) {
        return;
    }
    ...
}

void maybeUnregisterTouchExpansion(int index, MountItem mountItem) {
    if (this == MountItem.getContent()) {
        return;
    }
    ...
}
3reactions
sushshringcommented, Jun 13, 2017

It seems I found the root cause of this. When touched, it did not seem to like the touchExpansion option at all. I don’t understand why that is the issue, but once I got rid of that it renders just fine now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Unexpected StackOverflowError in KeyListener - Stack Overflow
Every time you type a key your initial listener's (this') keyTyped method is called, that calls fixAnswers, and as the last step, it...
Read more >
How to Fix java.lang.StackOverflowError in Java - Rollbar
A java.lang.NoSuchMethodError is a runtime error which occurs when a method is called that exists at compile time, but does not exist at ......
Read more >
The StackOverflowError in Java - Baeldung
Let's start with the basics. When a method is called, a new stack frame gets created on the call stack. This stack frame...
Read more >
Article: Avoiding the StackOverflowError Exception
When a Boomi process is looping back onto itself it can easily use all stack space after a few hundreds iterations. An example...
Read more >
StackOverflowError in Java with examples - GeeksforGeeks
StackOverflowError in Java with examples ... StackOverflowError is an error which Java doesn't allow to catch, for instance, stack running out of ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found