-
Notifications
You must be signed in to change notification settings - Fork 208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DataBinding fixing #1305
DataBinding fixing #1305
Conversation
* Must use kapt to access data binding classes in test * Have to access another intermediate resource folder to get processed data binding layouts * New resource folder must be last to have priority
0f69351
to
12123ac
Compare
import android.annotation.SuppressLint | ||
|
||
/** | ||
* Running instrumented tests with Robolectric on Data Binding enabled library modules throws [NoClassDefFoundError] for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Snagged this from an associated thread about Robolectric having issues finding the same DataBinderMapperImpl. I can redo the comment here and link to the original thread for more context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this means clients would need to add this shim to their project as well which doesn't feel nice. Could we potentially do something with ByteBuddy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's a big concern. ByteBuddy could work as long as we can access the module's package to find the generated class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is interesting. Note that in #1016, the repro project is an Android application, not a library project. This is because DataBinding generates DataBinderMapperImpl
in the app module.
Now we could support that, but coupled with my comment about <data>
, to what cause?
I'm of the opinion that we should strive to support ViewBinding style inflations, viaFooBinding.inflate(..)
, but not the full suite of possibilities that DataBinding offers. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nonetheless, if the feeling is a resounding "yes, we should support databinding", then I think the way to tackle this unpleasant dev experience would be to check for the Gradle option being set in the buildFeatures, pass that as a System Property ("paparazzi.androidx.databinding.enabled") and load this impl in Paparazzi.kt when that property is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we still need the DataBinderMapperImpl
to support ViewBinding so I can look into setting up a system property
c451bcc
to
bba4fa6
Compare
@@ -0,0 +1,10 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<layout xmlns:android="http://schemas.android.com/apk/res/android"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried using the <data/>
tag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet but I can add a test for that next
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think let's not support <data/>
tags; I feel like it's a Pandora's box and not worth the squeeze.
The original issue in #1016 doesn't use it, and Paparazzi takes a fairly opinionated stance about separating business logic from view. Instead, users can grab a handle to textview and set their logic-driven properties directly in test code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would be fine. Data binding is in maintenance mode (according to this issue about migrating it to ksp) and it seems like google is pushing folks towards Compose instead. With this in mind, just supporting the view binding may be good enough
assertThat(config.projectResourceDirs).containsExactly( | ||
"src/main/res", | ||
"src/debug/res", | ||
"build/intermediates/packaged_res/debug" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting idea pulling this, looking at how AS handles it we could also do something similar in our LayoutPullParser
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed. I noticed similar, but I think our current AaptParser logic might need some refactoring. I'm exploring that now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
following up on this: I debugged how LayoutLib renders fragment_dashboard.xml
(i.e., the repro from #1016 (comment)) in the IDE and this layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.dashboard.DashboardFragment">
<TextView
android:id="@+id/text_dashboard"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
results in this TagSnapshot hierarchy:
TagSnapshot{
androidx.constraintlayout.widget.ConstraintLayout,
attributes=[
AttributeSnapshot{layout_width="match_parent"},
AttributeSnapshot{layout_height="match_parent"},
AttributeSnapshot{context=".ui.dashboard.DashboardFragment"},
AttributeSnapshot{tag="layout/fragment_dashboard_0"}
],
children=[
TagSnapshot{
TextView,
attributes=[
AttributeSnapshot{id="@+id/text_dashboard"},
...
],
children=[]
}
]
}
In particular, note the AttributeSnapshot{tag="layout/fragment_dashboard_0"}
, which reminds me of the work we did in #196 to support Cash Card gradients.
Yea, this will be partly fixed in #1136 |
7492d96
to
8f99e9b
Compare
Related to #1016
BR
class when using the<data>
tagDataBindingMapperImpl
instead of requiring consumers to add one themselvesTwo issues I ran into trying to fix this. The first is that attempting to access any data binding from the test results in a class not found for
DataBindingMapperImpl
. One does get generated but it is not accessible. I found a similar issue related to Roboectric where one of the posts mentioned creating a fake version of the class and adding the actual version via reflection which worked.Here is the example version.
I tweaked the implementation since we are unable to query the application package name from the unit test variant.
The second issue is that paparazzi is not loading the processed layout files which is why it's erroring when parsing the
layout
tag. I found an additional resource directory underbuild/intermediates/packaged_res/debug
that has the processed layouts. Adding this to theprojectResourceDirs
in the paparazzi plugin allows the correct layout to load.important this has to be the last resource directory. I tried having it first but it was defaulting to the original, unprocessed layout which fails on the
layout
tag.