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
Completely generate DataBinding models #187
Comments
Sounds pretty cool! Any ideas about R parsing? Something similar to this part which was taken from Butterknife? |
@geralt-encore yeah, it would be cool! I just put up my WIP code for the databinding at #188 which this would build upon. It seems like you understand it. Although I don't think we would actually generate the handwritten model, since then we would need to generate the I'm thinking the generated model name would be based on the xml name. Camel cased, and possibly appended with something ( And yes, I am thinking of parsing the R tree like butterknife does. I removed that R tree parsing in Epoxy since I figured out a simpler approach, but we could add it back in. Basically for a layout like
We should be able to identify the As I type this out though, I realized the R class doesn't give you access to the xml layout. And I'm not sure we can look up an Xml file in an annotation processor, so that approach might be a dead end. Alternatively we could use a gradle plugin to look at all xml files and find ones with One other approach could be to have our annotation processor look for generated classes that extend Haha, sorry, I just started thinking about this this morning, but I think it has promise. Happy to hear your ideas and it would be great if you can work on it. I should be able to merge my data binding PR tomorrow or the next day |
I'm trying to learn exactly what databinding does under the hood. https://realm.io/news/data-binding-android-boyar-mount/ is a bit helful, but doesn't got into too much detail. Sounds like some sort of plugin at compile time. If we go the gradle plugin route I think that could be a cool way to automatically make models for all databinding layouts, no extra work required. If we did the annotation approach where you declare what layouts you want models made for I think we can take that layout name, figure out what the expected DataBinding name is, and then try to look that up. I'm still not sure if it will be generated and accessible at that time though. |
@geralt-encore I did some testing, and I think it will be possible to do this with an annotation processor! If we know the name of the binding class generated for the layout (by default it's based on the xml name) then we can look it up in the processor by name. For We can then look at enclosed elements to see the methods, and look at the setters to get the variable names and their types. The only trick is the binding class is not available on the first round of processing so we just need to make sure the processor works on multiple rounds. Right now I'm thinking we might do a package annotation with a list of layout resources as the params (I mentioned this above). The processor can look for that annotation, then use the layout resources to get the expected names of the binding classes, look those up, generate a model with normal epoxy annotations in the package that the package annotation was in, and then the normal epoxy processor should pick those up and generate the normal It could be confusing to have two generated models though, so we could just go with one. but that would probably be more work to modify the large model processor to do that. Any other ideas about how to declare the layouts besides a package annotation? This seems like a decent approach, unless you liked the idea of a gradle plugin? That is a bit appealing to not have to declare anything at all, but it could also be a bit weird and be a lot more work. |
@geralt-encore Were you interested in working on this? If not I'll start |
Sorry, that didn't answer you earlier. Yeah, it seems like a good approach and I am interested in working on this. Do we need to do anything to be sure that processor works on multiple rounds? As far as I remember it should be handled automatically, right? |
@geralt-encore Great! I realized that the R class parsing in The rounds do happen automatically. However, we do something a little hacky in Eg, if the controller has automodels like
Then Like I said, hacky :P if you can think of a better way to do it, be my guest! The problem is that the databinding classes are generated the first round, so we can't access them to look up the setters until the second round, so our databinding models aren't generated until the second round. But the controller processor will have already run, so if any of the databinding models were used in So, we would need some good way of delaying the auto model code generation until after the databinding models are generated. We should be able to run the controller processor on the annotations to collect the necessary data, and then just hold onto that and wait until a later round to actually write the java code |
@geralt-encore I refactored the layout processing in #190, and stubbed out the remaining work in the I haven't tried to fix the multiple round support, but hopefully your understand my notes about it. If not I can try to clarify further. The intermediate models should be an easy solution (I hope), but it's also not my preferred solution since it creates two models, and users would only ever need the I think it wouldn't be that hard to skip the intermediate model and generate the Thanks for working on this! let me know if you'd like help. |
@elihart cool! I'll take a look as soon as I can. |
@geralt-encore Awesome! keep me posted on how it goes. I would also need to add fields to the generated class to support #171, so might as well do it now. The |
@geralt-encore Hey, how's it going with this? |
Didn't have that much time lately 😔 |
No worries, I've been busy too :( The intermediate approach is fine, it's a good foundation we can release with to start and then build upon :) Let me know if you want any help or code review! |
@geralt-encore I've been working on generating models for litho components. In order to support that I've refactored how the model generation works to make it easy to create just a generated class without the user created model class as an intermediate step. This should make it easy to generate the databinding models. So, if you haven't worked much on it yet you might want to hold off until I finish this refactor. |
Well, I made progress faster than I expected #202 :P If you don't have time to work on this databinding generation I can start it. Do you have any initial code started? |
I haven't done much really so I can hold off until #202 will be merged. I should have enough time to deal with it now, so now worries :) |
Great! 202 is merged, and I also just did #204 to lay some more foundation. The main thing that does it change the processors to work with multiple rounds. The way it is set up now I've stubbed out the calls in the correct places so that the databinding classes will exist (I think). I also updated the code generation to get the layout resource off the generated databinding model. that could be cleaned up a lot, but it (should) work. The main job of parsing the databinding class and building the model and attribute info is wide open :) The code is a bit rough so feel free to clean it up as you go. Thanks! |
Here is my WIP implementation. |
Thanks for starting on this, I'll check out your work and see what is going on. |
@geralt-encore I believe you need to enable databinding in the build.gradle file of the integration test module |
@elihart thanks for looking into it. It is already enabled. |
ah right, hmmm. The code looks pretty great overall and nothing stands out as wrong. I'll pull the branch sometime today and poke around a bit. |
I just was thinking... Isn't data binding has nothing to do with annotation processing? Looks like it invoked by some Gradle task and probably it happens after/during the annotation processing task. So waiting for the last round doesn't actually change anything in that case. Or am I missing something? |
From my understanding, databinding uses both a gradle plugin and annotation processing. Just found the problem. The module name is wrong. the class is generated at I'm a bit confused about what is going on with the package. In the android manifest of the integration test module the package is defined as The integration test module has an R file generated for both Since we use the R file in I'll keep looking into this. |
I also was thinking about this but changing package didn't solve anything. You used the same package for accessing |
The BR class seems to be generated in both the packages (like R) :( weird stuff, I've got some meetings for a while but I'll look more later. let me know if you have ideas! I wonder if we rename the manifest package of the integration test module it might work better, since right now there multiple modules with that package name and it seems to cause issues sometimes |
Yeah, I am confused as well =( |
oh... I completely missed this line in the data binding docs https://developer.android.com/topic/libraries/data-binding/index.html#custom_binding_class_names So that explains everything I think. Should be an easy fix to adjust for that. |
Looks like it crashes in a different place now. Can't figure out where exactly but it is still a progress anyway. |
@elihart thanks a lot for your help! Turned out we were right about package name but I missed it in a first place because I was getting another NPE. |
ah good. Glad I could help! Let me know if you'd like help tracking now NPE's. I've been dealing with those lately, it's annoying that sometimes the stacktrace is not included. |
I am almost done with #183 and it got me thinking that all somebody should really have to do is define a list of xml layouts that they want to use with databinding, and we could generate the whole EpoxyModel for them.
For example, with the upcoming support they would have to write a model like
but instead we could have them define layouts in an annotation like
@EpoxyDataBindingLayouts({R.layout_my_databinding_layout1, R.layout_my_databinding_layout1})
and the annotation processor could inspect the R tree at process time to get the data variables and build the model completely. This is safer too because it guarantees that the variable names of the model stay in sync with the data names in the layout.
I don't think this is too hard - the R parsing would be the hardest part. It isn't super important because it isn't a lot of work to create a model like above, but it would be a nice boilerplate saver and I think it would be pretty cool.
The text was updated successfully, but these errors were encountered: