I am trying android data-binding and I am really amazed with its capabilities. It really shifts all the getters and setters of views to a single place (layout files or custom binding adapters) .
But, I don't understand what is the use of the namespace here? I was reading a recent article from George on Medium here, and he mentioned that:
Anything in the application namespace doesn’t need any namespace in the parameter, but for attributes in the android namespace, you must give the full attribute name including the “android.”
So, if I don't give a namespace, it works. My custom attributes are namespaced with xmlns:app="http://schemas.android.com/apk/res-auto" . I really don't know what that means.
Say I have a text view where I am doing this like this (hardcoded strings just for example) :
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='#{"Created By:" + user.name + " on " + user.time}' />
It's really good as I can provide arguments here:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:createdBy="#{user.name}"
app:createdAt="#{user.time}" />
And handling that code in Java by setting that text to the same as on above example. This provides an easy to use and understandable code for the layout files.
But, this arguments can collide sometimes. If I am using this at 2 different places with 2 different formats like Created by User A on 7/10/2016 and From User A (7/10/2016). This both can requires same arguments as I showed in second example. How can I distinguish them?
I can also provide third argument like app:format and so that my custom binding function can understand, but can namespaces play the important role here? Can I provide a custom namespaces for multiple data-binding elements and handle them accordingly in my binding adapters? Or namespaces will just be ignored as George mentioned in his article?
In the official documentation they have used bind: namespace and in binding adapter methods they have provided namespace there. I am little bit confused about namespaces' role in data-binding.
XML is very flexible and allows you to provide any number of namespaces. Android, however, isn't (yet) flexible enough to handle more than two -- android and your application's namespace. Android data binding doesn't distinguish between any application namespace name. e.g. bind: or app: doesn't matter because they all refer to http://schemas.android.com/apk/res-auto.
So, the answer to your question is "No." Namespaces won't really help. You could use the android namespace -- assuming there aren't unfortunate collisions. That only extends your flexibility from one to two and I'm pretty sure you want something better than that.
This specific example is perfect for string formatting expressions:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='#{#string/createdBy(user.name, user.time)}' />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='#{#string/fromUser(user.name, user.time)}' />
But generally speaking, you'll have to either use different attributes names for different uses or add an attribute for the differentiator as you suggested.
Related
Is it not possible to simplify the name of a custom element in an Activity XML file?
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
android:id="#+id/myView"
app:newAttr="value" />
Say for example I have a CustomView control. Do I always have to put "com.library." in front of "CustomView" or is it possible to use xmlns:custom in a FrameLayout so that I don't need to?
This is what I would like to see (if possible):
<CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
android:id="#+id/myView"
app:newAttr="value" />
No. You must specify the fully qualified name of the custom view class. The custom attribites belong to a different namespace. So you nee to have
http://schemas.android.com/apk/res/[your package name].
That is why you have
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
It is necessary to specify fully qualified name of the custom view and hence
<com.library.CustomView
http://developer.android.com/training/custom-views/create-view.html
The docs does not mention any other solution.
Edit:
There seems to be a workaround as mentioned in the below link. Notice comments on both answers. The authors feels there is a little overhead involved. So its left you to use the below although i recommend you to follow the above method mentioned in the docs.
Using custom Views in XML without using fully-qualified class name
I would like to do something like
<TextViewPlus
android:id="#+id/settings_title_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#string/settings />
instead of
<com.my.really.super.long.package.name.that.wont.autocomplete.TextViewPlus
android:id="#+id/settings_title_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="#string/settings />
I figure I could just put custom Views in the (default) package, but that seems like a bad idea. (EDIT: And upon testing this, it doesn't work anyway) Is there a "good" way to do this?
No, AFAIK you will have to go with the full name.
LayoutInflater.setFactory(LayoutInflater.Factory) allows you to specify an object that performs custom view object creation given the tag name at run time. This could be used to achieve what you want to do. I'd call getFactory() first to retrieve the existing default factory object and use that for any view names that are not your custom views.
When I started developping android applications, I had a tendency to define custom R values wherever I need, in particular in layout files. For instance:
findViewById(R.id.customerName).setText(customer.getName())
with layout:
<TextView android:text="TextView" android:id="#id/customerName"
android:layout_height="wrap_content" android:layout_width="fill_parent" />
Now I realize, it might be better to use android.R instead.
findViewById(android.R.id.text1).setText(customer.getName())
with layout:
<TextView android:text="TextView" android:id="#android:id/text1"
android:layout_height="wrap_content" android:layout_width="fill_parent" />
What practice do you follow? What are the advantages and disadvantages of each?
android.R is meant for utilizing resources built in to the operating system.
There are many images/layouts/etc... that come with the operating system that you can just reference using android.R
if you are referencing your own resources that you have created, most always use R. and in most situations I recommend trying to stay away from the built in resources as they change version to version.
Custom. The system-provided IDs come with a risk of referring, in code, to a resource that is not present in the project. Customs IDs exist iff there's a corresponding resource - a drawable, a view, a layout or what have you.
There is no big advantage or disadvantage of the framework id vs the custom id in layouts.
Advantages of using framework identifiers:
Avoid the creation of more identifiers. Saves one field in the apk (and there is an apk size limit).
Must be used in some situations, like ListActivity
Drawbacks of using framework identifiers:
Don't provide a descriptive name
In both practices
The code will work in the future
Missing references are discovered at runtime, and hidden at compile time
I thought the the samples in the SDK would help me take a decision, and (guess what?) it doesn't. The Notepad and LunarLander applications use the android.R.id for the view identifiers, whereas the ApiDemos project uses custom identifiers.
Best practice for GestureBuilder which mixes both approaches? (#+id/addButton and #android:id/empty)
IHMO, worse practice for HelloActivity and JetBoy which define #+id/text #+id/Button01... This is not descriptive and could have been replaced by (#andoid:id/button1, or by #+id/startButton)
You need your own R.java class as it contains references to all of your resources (layouts, images, strings, etc.)
If you want to get a reference to a View with id of "myView", you would use R.id.myView.
If you want to get a reference to built-in Android resources, you would use android.R.id.text
Take a look at the following page:
http://developer.android.com/guide/topics/resources/accessing-resources.html
After taking a look at theming for Fede's UberMusic I came across the file album_screen.xml. Below is the source of that file. Basically I noticed that his themes have the ability to use custom views that are a part of his application, and that they have this XML namespace at the top theme. I am missing the connection as to how he is able to apply his attributes to views that he does not control, and how Eclipse will compile the cod below without fail. I placed the URL http://schemas.uberdroidstudio.com/theme into my browser's address bar but nothing came up, and I cannot figure out where/ how Eclipse knows the attributes that the namespace supports. Thank you ahead of time for your help.
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:theme="http://schemas.uberdroidstudio.com/theme">
<TextView
android:id="#id/artist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.0"
theme:textFilter="uppercase" /> <!-- This is the interesting line -->
I suspect that the theme:textFilter="uppercase" line isn't actually having an effect on the (apparently vanilla) TextView.
As for the URL of the namespace, it is interesting that you can't access it, since it does not appear to be a local styleable (Android would have you refer to a local styleable namespace as http://schemas.android.com/apk/res/your.package). +1 for novelty.
The solution is actually not as complicated as I originally thought. XML namespaces are arbitrary strings that just need to be unique. If your namespace does not start with http://schemas.android.com/apk/res then it is not validated and the APK package is not checked for declare-styleable or the like.
Now a custom namespace if very simple to implement, as illustrated by this code snippet in GitHub. Finally, applying custom XML attributes to "normal" widgets can be accomplished by using the LayoutInflater.Factory and calling setFactory before you inflate your views. Throw it all together and you have a highly theme-able, XML driven application like Fede's UberMusic.
This page in the Android documentation defines an element id as follows:
<TextView android:id="#+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Type here:" />
However this page defines it as:
<EditText id="text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:textColor="#color/opaque_red"
android:text="Hello, World!" />
I thought I had a decent understanding of what was going on until I saw this second example. In the first case, you need the + character so that id 'label' is added to the R file, correct? In the second case, would the EditText's id not be added to the R file because it does not contain the + character?
Also, the second example does not include the android namespace on the id. Does having or not having the Android namespace affect whether that id will be added to the R file?
Thanks for any clarification.
This format without the android: namespace
id="text"
is from an earlier version of the Android SDK.
You are correct in your initial assessment. It's worth noting that the second id tag
<EditText id="text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:textColor="#color/opaque_red"
android:text="Hello, World!" />
Is missing the android: namespace so it actually isn't an android xml tag. The first one is an example of how to add that view's id to the R file so you can access it in your code. To be honest, I'm not sure what the purpose of the id in the second example is*, but I know that android wouldn't know what to do with it. The first one is the correct syntax.
*This is just speculation, but I'm willing to bet it was a typo somebody didn't notice or didn't care to fix because they were trying to illustrate something else.
The plus-symbol (+) means that this is a new resource name that must be created and added to our resources (in the R.java file). There are a number of other ID resources that are offered by the Android framework. When referencing an Android resource ID, you do not need the plus-symbol, but must add the android package namespace, like so:
android:id="#android:id/empty"
Taken from Declaring Layout | Android Developers in the ID section.
However, in your second example there is no #android:id/ provided before the id text so to be brutally honest, I have never seen that notation before and wonder if that could be a typo on the author's part.
The second example is wrong. The attribute is always android:id and the value should be either #+id/myId (to create a new id called "myId") or #id/myId (to use an already defined id called "myId".) Using #android:id/theId lets you use ids defined by the android platform.