robinhood / ticker

An Android text view with scrolling text change animation
https://medium.com/robinhood-engineering/hello-ticker-20eaf6e51689
Apache License 2.0
4.38k stars 462 forks source link

android:text should not force user to specify character list in XML #84

Closed bjarn closed 6 years ago

bjarn commented 6 years ago

Hello,

Since the latest update from 1.2.0 to 1.2.1 or 1.2.2, I am receiving the following crash: 01-19 23:20:51.007 20955-20955/<package name> E/AndroidRuntime: FATAL EXCEPTION: main Process: <package name>, PID: 20955 java.lang.RuntimeException: Unable to start activity ComponentInfo{<package name>/<package name>.activities.<activity name>}: android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class com.robinhood.ticker.TickerView at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class com.robinhood.ticker.TickerView Caused by: android.view.InflateException: Binary XML file line #0: Error inflating class com.robinhood.ticker.TickerView Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:334) at android.view.LayoutInflater.createView(LayoutInflater.java:647) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730) at android.view.LayoutInflater.rInflate(LayoutInflater.java:863) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) at android.view.LayoutInflater.inflate(LayoutInflater.java:515) at android.view.LayoutInflater.inflate(LayoutInflater.java:423) at <package name>.fragments.<fragment name>.onCreateView(<fragment name>.java:126) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2354) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1419) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809) at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:799) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2580) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367) at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229) at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3221)

When reverting ticker to version 1.2.0, it works again. I am using the latest Android API 27 in Android Studio with Gradle 4.

naturalwarren commented 6 years ago

Ticker's sample app uses Gradle 4 and targets SDK 27 without troubles. Double check your XML?

bjarn commented 6 years ago

@naturalwarren I have verified my XML, it is valid and works with Ticket 1.2.0. It breaks when using 1.2.1 or 1.2.2. It also shows correctly in the preview window in Android Studio for 1.2.0 and 1.2.2. When using 1.2.1, the preview window also shows a grey bar indicating that the view isn't working. Here is my XML:

<com.robinhood.ticker.TickerView
    android:id="@+id/count"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="end"
    android:layout_marginTop="@dimen/textMarginTop"
    android:singleLine="true"
    android:gravity="end"
    android:text="@string/error_value_not_available"
    android:textAppearance="@style/BoldTextView"
    android:textColor="@color/primaryText"
    android:textSize="@dimen/textSize"
    android:textStyle="bold" />
naturalwarren commented 6 years ago

Your XML looks fine. I have a feeling this is related to your layout/view hierarchy. The number of calls torInflate() in the stacktrace indicate its pretty deep/broad. What layouts is the TickerView being wrapped in?

If you could provide a small sample project that reproduces the issue I'd love to take a closer look.

jinatonic commented 6 years ago

not much data in the stacktrace, like @naturalwarren pointed out, please share more code or see if you can reproduce your issue in a sample project. Thanks!

bjarn commented 6 years ago

My TickerView is wrapped in the following layouts, by order: FrameLayout > CoordinatorLayout > NestedScrollView > LinearLayout > GridLayout > CardView > LinearLayout > TickerView

This is deep indeed. But for 1.2.0 this is not a problem. I also read that there are other libraries having issues with inflating since Android 8.

I also updated my support libraries to 27.0.2.

Here is a sample project which contains the structure I mentioned earlier and it crashes for me too (I know, it is very primitive, put some random hard coded values for dimensions etc): https://github.com/BjarnBronsveld/TicketIssueDemo

naturalwarren commented 6 years ago

Thanks for the sample project @BjarnBronsveld.

1.2.1 added support for android:text to TickerView. Using this attribute requires you also specify app:ticker_defaultCharacterList. Add that tag with the appropriate value (alphabet or number) and you'll be good to update to 1.2.2. Note that if you just want to see Ticker show a placeholder value in layout preview you can use tools:text.

@jinatonic This feels a little bit like a footgun in the API. One thing we could do is not require a character list to be set when initially configuring TickerView text from layout XML. No animation takes place there so we don't really need it yet. Thoughts?

bjarn commented 6 years ago

@naturalwarren Thanks, I did not add that attribute indeed. But there's one issue, I can set the attribute to number but not too alphabet. It gives me a Cannot resolve symbol 'alphabet'. Not sure if I am missing something here.

Edit: 'number' works well for my app. So for me this issue has been fixed. Thanks :)

naturalwarren commented 6 years ago

Alphabet support was actually landed in #83 which will go out as part of Ticker 2.0.0 - stay tuned :)

Glad to hear it's all working!

jinatonic commented 6 years ago

Ah great point. android:text should indeed not force the user to specify character list in XML. will use this ticket to track that work.