The class ViewDataBinding provides setLifecycleOwner() and setLifecycleOwner()
but when I use it in xml such as
android:onClick="#{()->InteractionPresenter.toggleFeedDiss(getLifecycleOwner())}"
it will turn out an error like this
[databinding] {"msg":"Could not find identifier
\u0027lifecycleOwner\u0027\n\nCheck that the identifier is spelled
correctly, and that no \u003cimport\u003e or \u003cvariable\u003e tags
are
missing.","file":"/Users/maxz/AndroidStudioProjects/ppjoke/app/src/main/res/layout/layout_feed_interaction.xml","pos":[{"line0":34,"col0":71,"line1":34,"col1":84}]}
so if I want to use LifeCycleOwner in data-binding with lambda, I have to declare another variable like
<variable
name="lifeCycleOwner"
type="androidx.lifecycle.LifecycleOwner" />
then I will use my own variable,it works
but how can I get a lifecycle owner by the first way?
To achieve first approach, You have to pass fragment instance to your layout.
<variable
name="fragment"
type="androidx.fragment.app.Fragment" />
And then use
android:onClick="#{()->InteractionPresenter.toggleFeedDiss(fragment.viewLifecycleOwner)}"
Related
Trying to dynamically set the layout using databinding but I can't seem to get the ternary operator to work right. Must be missing escape character or something.
<include
android:id="#+id/setting"
bind:settingsViewModel="#{settingsViewModel}"
layout="#{settingsViewModel.configFlag ? #layout/settings_v1 :#layout/settings_v2}" />
Seems simple enough but errors with "****/ data binding error ****msg:included value ... must start with #layout/. "
The answer to this is that you cannot do this. Layout is called before and so this logic cannot be done before hand.
While studying android data-binding, my colleague told me that the android data-binding can be null in few cases, also when one layout includes another layout with data-binding, the generated data-binding file annotate the binding of another layout as #Nullable. My question is can data-binding be null and if yes when?
Data binding is a blueprint.
A class that is created at compile time when it sees the "layout" tag.
The blueprint class will be named LayoutNameBinding Pascal Case.
Just like any other class, it is non-existent until you reserve memory for it and new it up.
So when you use the data binding utility on the onCreate it creates the class and you can store that in a local variable for using later.
example:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.activity = this
binding.iBindingRecyclerView = this
binding.navHeader?.activity = this
setupNavigationDrawer()
}
"layout root xml files that have other layout root xml files nested in them or named include layouts" will be added as classes inside the parent NameOfLayoutBinding class. These will not be null as they are auto generated at compile time so when you new up the parent, the children will exist.
So a databinding will not be null if you are referring to the auto generated class and if you are newing it up in your onCreate method appropriately.
Now a failed binding event due to a null object can happen if you didn't pass in the variable that you are binding to, but that is not the question you asked.
Hope that helps, if you meant something different, please digress.
Finally, after so many years found an explaination for this. In case you are manually executing the DataBinding.inflate function then the returned DataBinding won't be null.
For auto generated bindings (i.e. when you include a layout and binding is generated and assigned to a variable in the parent layout binding), the data binding can be null based on some situation.
E.g.: Let's say we have layout as follow:
Portrait Mode layout: /src/res/layout/activity.xml
<LinearLayout ...>
<include
android:id="#+id/main_content"
layout="#layout/main_content_layout"
/>
</LinearLayout>
And for Lanscape mode: /src/res/layout-land/activity.xml
<LinearLayout ...>
<include
android:id="#+id/sidebar"
layout="#layout/sidebar_layout"
/>
<include
android:id="#+id/main_content"
layout="#layout/main_content_layout"
/>
</LinearLayout>
Now here as the multiple layout files are for same purpose but with different configuration (lanscape mode and portrait mode) the Android DataBinding will generate ActivityBinding.java file. Now here the developer would need to access binding for both sidebar and main content using object of ActivityBinding.java class. As the sidebar is not present in portrait mode layout file, the binding file won't have any reference. Hence the reference for sidebar binding would be kept as Nullable.
Hence, for the layout files with same name for different configuration and with different view hierarchy, the inner binding object generated can have null value, due to which the data binding may have Nullable binding fields.
Android provided new concept of showing data on UI via data binding. I tried implementing it on one of my application. While implementing Lambda expression as a click handler of my button, I required a constant i.e.View.VISIBLE for comparing it in my expression. But when I write below code:
android:onClick="#{(activity_main)-> activity_main.getVisibility() == View.VISIBLE ? eventHandler.eventHandlerViaListenerBinding(true) : eventHandler.eventHandlerViaListenerBinding(false)}"
It is giving me an error:
Error:(57, 83) Identifiers must have user defined types from the XML file. View is missing it
My question is how can I import constants in the xml?
Thanks in advance.
Inside your data tag add this.
<import type="android.view.View" />
or Just upate the build.gradle of the library to enable databinding as well as in the main project:
dataBinding {
enabled = true
}
I am currently trying to pass the resource id of a raw resource to a special View using the new Android data-binding mechanism. When I try something like this
...
app:bufferedSvg="#{ViewModel.headerCollapsed ? #raw/header_expand : #raw/header_collapse}"
...
I get an error <expr> expected, got '#'. The raw resources exist and cannot be turned into another kind of resource as they contain SVG data.
Is this a bug of Android data binding or is this intended behaviour?
At least I found a workaround meanwhile. Import the R class:
<data>
<import type="com.yourdomain.R"/>
<variable name="ViewModel" type="com.yourdomain.ViewModel"/>
</data>
...
<com.yourdomain.yourview
...
app:bufferedSvg="#{ViewModel.yourchoice ? R.raw.raw_resource1 : R.raw.raw_resource2}"
...
/>
Hope this helps someone who runs into the same problem. Would still like to know whether the #-notation for raw resources is planned to be supported or not.
I've read the documentation about Fragments in the Android Developer Guide and I've seen that sometimes they specify the class to instantiate with the Fragment tag attribute android:name and sometime they use the class: attribute:
<fragment
android:name="com.example.news.ArticleReaderFragment"
android:id="#+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment
class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="#+id/titles"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
Are android:name and class: interchangeable? If I use the autocompletion function in Eclipse, they both show the same documentation tip (i.e. the attribute provides the class name to be instantiated). Maybe you must use the second one when the class to be instantiated has a name which is different from the java file name, like TitlesFragment which is in the FragmentLayout.java file? Or can I use the syntax package.fileDOTjava$Class also with the android:name attribute?
I'd like to have some documentation for XML tags and attributes as for Android Java Classes (I've asked about it in another question).
As Activity.onCreateView source says:
String fname = attrs.getAttributeValue(null, "class");
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
if (fname == null) {
fname = a.getString(com.android.internal.R.styleable.Fragment_name);
}
That seemingly means that program looks "class" attribute first. And on fail looks "name" attribute.
So as far as it's true using "class" if more efficient.
Are android:name and class: interchangeable?
Presumably, yes. I have only used class, and that seems to be what most of Google's examples use, but I do see where they use android:name in some samples. Unfortunately, there is no formal and complete documentation for <fragment>.
Sorry all experts are here, I may be wrong but as per my knowledge android:name attribute of fragment is used to find fragment, when we use getFragmentByTag() method of fragmentManager class.
also android:class attribute is used to find fragment class which we generally include for static fragment.
Hope this will help..
thanks