Override layout and databinding generated class on android

Viewed 570

I have the following bug while developing my app:

I'm building multiple app using some "default" library modules. Those library modules all use databinding and include default layouts and functionality. Sometimes I'll be required to change the UI of something found in the library modules and then I get into trouble.

Let's imagine the following scenario:

LibraryA:

  • Databinding enabled

  • Create LibActivityA and layout_A.xml (root tag is )

  • Inside LibActivityA use the LayoutABinding to your free will

AppB:

  • dependency on LibraryA

  • databinding enabled

  • Some activity inside AppB launches LibActivityA and everything works fine (no layout changes from LibraryA)

  • I do a release apk and can use it properly

AppC:

  • dependency on LibraryA

  • databinding enabled

  • I have a request to move an element found in layout_A.xml to the bottom of the screen let's say

  • I create another layout_A.xml file (root tag is ) and adjust what's needed (while keeping all other members to avoid runtime errors).

  • I run the app and at runtime I get a class cast exception

  • Quick search I find that the generated LayoutABinding is in my app package so I use https://developer.android.com/topic/libraries/data-binding/generated-binding#custom_binding_class_names to move LayoutABinding to the exact same package as found in LibraryA.

  • run the app again and everything is fine, champagne bottles out!

  • Hit generate signed apk to do a release build and get the following error: Execution failed for task ':app:transformDexArchiveWithDexMergerForVariantStoreRelease'.

    com.android.build.api.transform.TransformException: java.lang.RuntimeException: java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes. Program type already present: com.company.librarya.databinding.LayoutABinding

I've searched the whole StackOverflow and internet and it seems nobody managed to successfully do what I want: overwrite the resource file from a library that uses dataBinding in order to have a slightly different view for some Apps that use the lib. Before using databinding everything went smoothly, indeed I had to be sure findViewByIds didn't return null and so but I could use the new layouts.

1 Answers

Somehow I've ended up digging inside the implementation of DataBinding classes and excluded errors one by one. What I've ended up in doing is:

AppC:

  • I create another layout_A.xml file BUT root tag is NOT anymore so it doesn't give the class cast exception; I adjust what's needed inside layout file.

  • LibActivityA uses DataBindingUtil.setContentView() so after resource merge the R.layout.layout_A will be the one from AppC

  • inside layout_A.xml from AppC I manually set the tags on views: root tag gets tag = "layout/layout_A_0", any direct childs of type ViewGroup get tag = "binding_[child number]".

Setting the tags manually seems to make the latest DataBinding generated classes work as expected. I'm very sure this is not the way to do this but it's the only way I've found without removing databinding completely :(

I'm very sure this is not how we're supposed to use the DataBinding library so I've opened up a ticket here: https://issuetracker.google.com/issues/135043330

Related