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.

Spec recreated when the visibility of the soft keyboard change

See original GitHub issue

Version

implementation 'com.facebook.litho:litho-core:0.8.0'
implementation 'com.facebook.litho:litho-widget:0.8.0'
compileOnly 'com.facebook.litho:litho-annotations:0.8.0'
annotationProcessor 'com.facebook.litho:litho-processor:0.8.0'

Issues and Steps to Reproduce

I have a Spec that create a Recycler that might contains multiple components of different types (text, checkbox, radio buttons, etc.).

Here is the main spec :

@LayoutSpec
public class LithoActivitySpec {

    @OnCreateLayout
    static ComponentLayout onCreateLayout(final ComponentContext c, @Prop FormDescription formDescription,
                                          @Prop FormFieldSpec.FormFieldListener listener,
                                          @Prop ButtonSpec.ButtonClickListener buttonListener) {

        final RecyclerBinder recyclerBinder = new RecyclerBinder.Builder()
                .layoutInfo(new LinearLayoutInfo(c, OrientationHelper.VERTICAL, false))
                .build(c);

        final Component recycler = Recycler.create(c)
                .binder(recyclerBinder)
                .build();

        bindDescriptionToRecycler(c, recyclerBinder, formDescription, listener);
        return Column.create(c)
                .child(Button.create(c)
                        .text("validate")
                        .listener(buttonListener))
                .child(recycler)
                .build();
    }

    private static void bindDescriptionToRecycler(ComponentContext c, RecyclerBinder recyclerBinder,
                                                  FormDescription formDescription,
                                                  FormFieldSpec.FormFieldListener listener) {
        List<RenderInfo> renderInfos = new ArrayList<>();
        for (ElementValue elementValue : formDescription.elementValues) {
            ElementValueType elementValueType = elementValue.getElementValueType();
            renderInfos.add(ComponentRenderInfo.create().component(
                    FormField.create(c)
                            .text(elementValueType.getName())
                            .dataType(elementValueType.getElementValueDataType())
                            .elementValueTypeId(elementValueType.getId())
                            .listener(listener)
                            .build())
                    .build()
            );
        }
        recyclerBinder.insertRangeAt(0, renderInfos);
    }
...
}

And here is the spec that will build the correct component depending of the DataType:

@LayoutSpec
public class FormFieldSpec {

    public static final int TEXT_SIZE = 16;

    @OnCreateLayout
    static ComponentLayout onCreateLayout(ComponentContext c,
                                          @Prop String text,
                                          @Prop ElementValueDataType dataType,
                                          @Prop String elementValueTypeId,
                                          @Prop FormFieldListener listener) {
        return Row.create(c)
                .paddingDip(YogaEdge.ALL, 16)
                .child(Text.create(c)
                        .text(text)
                        .verticalGravity(VerticalGravity.CENTER)
                        .textColor(ContextCompat.getColor(c, android.R.color.tab_indicator_text))
                        .textStyle(Typeface.BOLD)
                        .textSizeSp(TEXT_SIZE)
                        .isSingleLine(false)
                        .widthPercent(33.0f))
                .child(getValueComponentLayout(c, dataType, elementValueTypeId, listener))
                .build();
    }

    private static ComponentLayout getValueComponentLayout(ComponentContext c,
                                                           ElementValueDataType dataType,
                                                           String elementValueTypeId,
                                                           FormFieldListener listener) {
        Component.Builder builder;
        switch (dataType.getType()) {
            case DATE: builder = FormFieldDate.create(c)
                    .elementValueTypeId(elementValueTypeId)
                    .allowFuture(((DateDataType) dataType).isFuturePossible())
                    .withTime(((DateDataType) dataType).isWithTime())
                    .listener(listener);
                break;
            case RADIO_BOOLEAN: builder = FormFieldRadioBoolean.create(c)
                    .elementValueTypeId(elementValueTypeId)
                    .listener(listener)
                    .valueTrue(((RadioBooleanDataType) dataType).getValueTrue())
                    .valueFalse(((RadioBooleanDataType) dataType).getValueFalse());
                break;
            case CHECK_BOOLEAN: builder =  FormFieldCheckBoolean.create(c)
                    .elementValueTypeId(elementValueTypeId)
                    .listener(listener)
                    .valueTrue(((CheckBooleanDataType) dataType).getValueTrue())
                    .valueFalse(((CheckBooleanDataType) dataType).getValueFalse());
                break;
            case STRING_LIST: builder = FormFieldVdoList.create(c)
                    .elementValueTypeId(elementValueTypeId)
                    .listener(listener)
                    .allowCustomValues(((StringListDataType) dataType).allowCustomValues())
                    .rootOption(((StringListDataType) dataType).getRootOption());
                break;
            default: builder = FormFieldString.create(c)
                    .elementValueTypeId(elementValueTypeId)
                    .listener(listener);
        }
        return builder.buildWithLayout();
    }
...
}

So if I have a Recycler that looks something like this:

Date
Radio
String
Check
String

Everytime I open or hide the keyboard, all my fields became empty. I set a breakpoint on the LithoActivitySpec#onCreateLayout() and I saw that everytime the keyboard change its visibility, this method is called.

Is it a bug or something I’m doing wrong on my side? Is their a onSaveInstanceState or something simillar to handle this?

Expected Behavior

I expect the opening/closing of the soft keyboard not triggering the onCreateLayout of my spec.

Side note

I’ve written this issue first on StackOverflow but I’m wondering what is the best place to post issues as this one? I see more traffic here on GitHub than on SO.

Issue Analytics

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

github_iconTop GitHub Comments

2reactions
pasqualeanatriellocommented, Nov 22, 2017

adjustResize will change the size of your LithoView. That means that a new layout needs to be computed for the new size and that’s why your onCreateLayout is called again. This behaviour is completely expected. Is it causing a problem for you?

0reactions
mihaelaocommented, Jun 20, 2019

Added docs and an example codelab to show how to save and restore state on app configuration change: https://github.com/facebook/litho/tree/master/codelabs/save-state-rotation

Read more comments on GitHub >

github_iconTop Results From Across the Web

Adjust layout when soft keyboard is on - android
This layout listens to measure changes, and if new measurements are < than the old ones, that means part of the screen is...
Read more >
Smoothly reacting to keyboard visibility changes in Android
When the soft keyboard is shown, Android forces the content to resize immediately (unless the windowSoftInputMode is set otherwise).
Read more >
Handle input method visibility | Android Developers
When input focus moves into or out of an editable text field, Android shows or hides the input method (such as the on-screen...
Read more >
Handling Input Method Visibility | Android Developers - MIT
When input focus moves into or out of an editable text field, Android shows or hides the input method (such as the on-screen...
Read more >
Do not emit keyboard changes in the constructor (I158204a0)
140808 : winrt: Do not emit keyboard changes in the constructor ... Code-Review ... which can cause problems when handleVisibilityChange is invoked.
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