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.
Related
I just began to learn data binding and I have some troubles in understanding its technique
in my following code, I have enabled data binding in the app Gradle file in order to use it and get rid of the findviewbyid() ... So I've created the binding variable as lateinit before the oncreate() function and then I initialized it in the on create fun like this: binding = DataBindingUtil.setContentView(this, R.layout.activity_main) and I will give you an example of a view in my XML file to complete on ...
<EditText
android:id="#+id/nickName_editText"
style="#android:style/Widget.DeviceDefault.Light.EditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/Margin"
android:layout_marginTop="#dimen/Margin"
android:layout_marginRight="#dimen/Margin"
android:hint="#string/hint"
android:inputType="textPersonName"
android:textAlignment="center" />
Back to the kotlin file what is the difference between these two lines of code below (*Both lines are working)
nickName_editText.visibility = View.VISIBLE
binding.nickNameEditText.visibility = View.VISIBLE
I know that we want to get rid of the findviewbyid() to make the app faster but why don't we do it like in the first line and we are not calling findViewById() too
I'm new to android development so I might not be able to understand that complicated answers :‑D
Thanks for helping!
These are both forms of data binding, binding.nicknameEditText is Androids implementation, and the recommended approach. "nickName_editText" is Kotlin data binding and has known bug issues, when you get into more complicated views they'll start to pop up.
Expanded your imports in the MainActivity, you'll notice the following import.
import kotlinx.android.synthetic.main.activity_main.*
The start indicates binding for all views in the layout.
If you "remove kotlinx.android.synthetic.main.activity_main.*" you'll notice that the "nickName_EditText" is now undefined.
You can also view the Kotlin byte code by
clicking on tools/Kotlin/show Kotlin ByteCode
If you click on "nickName_editText" you'll notice the bytecode for this section will be highlighted.
Hopefully, this answers all your questions
I'm trying to use data binding to assign a 'layout' attribute within an tag. I'm passing in a boolean value that tells me if the app is in dark mode. I use this variable to determine if I should assign a white button layout or a black button layout.
I've tried to just do this intuitively since I've seen people use data binding booleans all the time to assign values in xml.
<include
android:id="#+id/buy_with_google"
layout="#{ isDarkMode ? #layout/buy_with_googlepay_button_white : #layout/buy_with_googlepay_button_black}"
Error: ****/ data binding error ****msg:included value (#{ isDarkMode ? #layout/buy_with_googlepay_button_white : #layout/buy_with_googlepay_button_black}) must start with #layout/. file:[Redacted File Path] ****\ data binding error ****```
Does databinding just not work in a way that allows me to use logic to assign whole layouts like that?
This is not possible as the include is executed at compile time and doesn't know about your viewModel or any runtime parameters.
In all the data-binding examples that shows Generic data type handling developer.android.com uses real char < and >.
but when it comes to reality
I am getting below error.
The value of attribute "type" associated with an element type
"variable" must not contain the '<' character.
I've searched the web and found people use > for > and < for < as a fix.
Questions
Is this supposed to happen ? If yes why it's not mentioned in the docs ?
Is there any fix for this, where I can write the layout as given in the official docs? (without using corresponding html entity characters)
There's unlikely to be a change to this because layout files are still XML, this isn't really the fault of Android or DataBinding, you're going to need to use appropriate encoding for HTML entities within an XML document.
Using < isn't that terrible as a fix, as far as resolutions go, but if you'd rather avoid using it, then it may be an option to simplify your binding expressions to move logic away from the layout and into your variables.
The current advised method of doing so is with a ViewModel, which can be bound to the layout and expose observable LiveData values.
I can't give you a reason for it not being in the documentation besides that it's probably just not advised to do so.
Now they've updated the documentation
Where to see a list of all attributes of all view types in Android?
I got an impression, that ImageButton does not have enabled and pressed attributes. At least, they didn't work when I set them in XML. Also I found a lot of "guides" on how to make these button either disabled and/or pressed.
Simultaneously, when I bound them with data binding
<ImageButton
android:id="#+id/locate_button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_toRightOf="#id/bookmark_button"
android:enabled="#{activity.locateEnabled}"
android:pressed="#{activity.locatePressed}"
android:onClick="#{activity.onLocateClick}"
android:src="#drawable/locate_selector"
android:background="#null"
/>
they just worked. Both pressed and enabled. At the same moment pressed is even reported as unknown property by Android Studion spell checked!
So, what is it?
1) by-design behaviour and I just don't understand something (what?)
2) sugar from data binding library
3) hacking
4) ????
How to know, how poratble is this feature?
The answer is both 1 and 2. Data binding will allow you use an attribute to call any setter on a View. You can look at the data binding guide's section on attribute setters.
When you set the android:enabled attribute, you are using Android data binding's the automatic setters to calls setEnabled(). Android data binding sees the attribute name (enabled) and looks for a setter with that name and finds setEnabled(). The same is true for android:pressed -- there is a setPressed() method. Yay for convention!
android:onClick is a real attribute, but data binding doesn't use it. There is no setOnClick() method, either. Instead, there is a Binding Adapter that sets an OnClickListener to call your onLocateClick() method. There is a bit of magic involved in this that relies on the Annotation Processor that data binding uses to examine your code, but suffice it to say that it does this at compile time instead of using runtime reflection.
All event listeners should have Binding Adapters written for them with the same name as the event (as opposed to the listener name). So, you can also set android:onLongClick, for example. You may also be interested in the lambda syntax for events.
I'm not sure what you mean by "portable." Data Binding is usable at least back to Gingerbread (we claim Froyo, but really, who targets Froyo?), but you won't be able to transfer it to iOS or anything like that. All of Android data binding is done with a small runtime library and generated code. You don't have to worry about specific versions of Android.
I'm trying to search through my Android project's XML files for objects that do not contain a certain object.
My set of objects looks like this:
<View
android:id="#+id/obstacle3"
android:layout_width="#dimen/obstacle_width"
android:layout_height="#dimen/obstacle_width"
android:background="#drawable/play_portal"
android:layout_below="#+id/obstacle36"
android:layout_toRightOf="#+id/obstacle29"
ads:brother="#+id/obstacle21"
/>
<View
android:id="#+id/obstacle3"
android:layout_width="#dimen/obstacle_width"
android:layout_height="#dimen/obstacle_width"
android:background="#drawable/play_portal"
android:layout_below="#+id/obstacle36"
android:layout_toRightOf="#+id/obstacle29"
/>
<View
android:id="#+id/obstacle3"
android:layout_width="#dimen/obstacle_width"
android:layout_height="#dimen/obstacle_width"
android:background="#drawable/play_portal"
android:layout_below="#+id/obstacle36"
android:layout_toRightOf="#+id/obstacle29"
ads:brother="#+id/obstacle21"
/>
With this search,
<View(\s+[^>]*?)ads([^>]*?/>) I can find all Views that contain ads:brother attribute, but I want the inverse; I want to find all Views that do not contain ads:brother attribute.
I've tried numerous things to no avail. What am I doing wrong here?
__Insert mandatory disclaimer "don't parse xml with regex" here__
<View([^>](?!ads))*?\/>
See it in action
The idea is to check that after each matched character there is no ads following, thus there is no ads in the entire match.