Android Data Binding : Tricks and Magic
You can do a lot of awesome things while using the Android Data Binding library. Some will save you a lots of time and some will seem like magic. You can see the full source code for this tutorial here.
The parameter in the @BindingAdapter declares the name of the custom attribute we are creating. The the first parameter to the function marked with @BindingAdapter is always the type of the ui element we are using this custom attribute on. Next parameter is the value the attribute takes in the xml. An now we can use the :typeface attribute in our layouts.
And this is how our custom fonts look:
An that is it! Now we have an attribute we can use to set custom fonts on out sub classes of TextView like EditTexts and Buttons.
Next lets set an image from a url with a custom attribute.
First we need to define our binding adapter:
Next we use the new :srcUrl and :error attributes in our layout:
And this is how our image looks:
Lets begin by defining a model representing the data our adapter will use:
Next we create our adapter:
That's one clean adapter! Notice in the onBindViewHolder() method we dynamically set the variables from our list of AdapterDataItems. Also getItemViewType() returns the layout id in order for us to know which layout to inflate in onCreateViewHolder() method.
Next up lets create some custom attributes for RecyclerView:
Here we define custom attributes to set the :list of models and :layoutManager for our RecyclerView. Now you are all set to use this dynamic adapter with any RecyclerView and any row layouts.
Lets create some layouts for our rows:
This is the layout for a header row.
This is a layout for item row.
We will have a PersonPresenter interface handling all the clicks:
The activity:
In our Activity onCreate() we pass the list of models and the LinearLayoutManager to the binding instance. In getModelList() we created a list of models with header rows and info rows. layout_item_heading.xml binds to a string variable and that variable's id is BR.groupName. BR is a generated class with binding variable ids similar to R class. layout_item_info.xml binds to a Person model and that variable's id is BR.personModel. layout_item_info.xml also takes PersonPresenter for the row's onClick listener. In our case the ListExampleActivity implements PersonPresenter.onPersonClicked() method.
Result:
Custom XML attributes
You can create custom xml attributes and add them to existing UI elements. For example if you ever had to use a custom font files in your application you would always have to set the type face programmatically as the TextView or its sub classes did not have an xml attribute to set the custom type face file from xml. With data binding you can implement your own attributes quick and easy. First lets define our binding adapter.public class AttributeBindings { @BindingAdapter({"bind:typeface"}) public static void setTypeFace(TextView view, TypeFaceType tft) { Log.i("AttributeBindings", "setting typeface:"+tft); Typeface typeface = null; switch (tft) { case NORMAL: typeface = Typeface.createFromAsset(view.getContext().getAssets(), "fonts/CaviarDreams.ttf"); break; case BOLD: typeface = Typeface.createFromAsset(view.getContext().getAssets(), "fonts/Caviar_Dreams_Bold.ttf"); break; case ITALIC: typeface = Typeface.createFromAsset(view.getContext().getAssets(), "fonts/CaviarDreams_Italic.ttf"); break; case BOLD_ITALIC: typeface = Typeface.createFromAsset(view.getContext().getAssets(), "fonts/CaviarDreams_BoldItalic.ttf"); break; default: Log.w("AttributeBindings", "unknown typeface passed"); } if (typeface!=null) view.setTypeface(typeface); } }
The parameter in the @BindingAdapter declares the name of the custom attribute we are creating. The the first parameter to the function marked with @BindingAdapter is always the type of the ui element we are using this custom attribute on. Next parameter is the value the attribute takes in the xml. An now we can use the :typeface attribute in our layouts.
<layout> ... <TextView android:id="@+id/textItalic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="CaviarDreams Font ITALIC" app:typeface="@{TypeFaceType.ITALIC}"/> ... </layout>
And this is how our custom fonts look:
An that is it! Now we have an attribute we can use to set custom fonts on out sub classes of TextView like EditTexts and Buttons.
Next lets set an image from a url with a custom attribute.
First we need to define our binding adapter:
@BindingAdapter({"bind:srcUrl", "bind:error"}) public static void loadImage(ImageView view, String url, Drawable error) { Picasso.with(view.getContext()).load(url).error(error).into(view); }
Next we use the new :srcUrl and :error attributes in our layout:
<ImageView android:layout_width="150dp" android:layout_height="wrap_content" android:adjustViewBounds="true" android:src="@drawable/ic_image" app:srcUrl = "@{imgModel}" app:error = "@{@drawable/ic_broken_image}"/>
And this is how our image looks:
Dynamic Adapter Magic
As a full time Android developer I had a dream that one day I would no longer have to write repetitive adapters for RecyclerViews. Taking advantage of dynamic variables in Android Data Binding library we can finally write ONE adapter for ALL or our RecyclerViews.Lets begin by defining a model representing the data our adapter will use:
public class AdapterDataItem { public int layoutId; List<Pair<Integer, Object>> idModelPairs; ... }The AdapterDataItem model contains layout id field and a list of integer - object pairs. The reason for this is because any layout with data binding can have multiple variables and for dynamic variable bindings we need to know those variable ids for each layout in order to pass the data models from the code.
Next we create our adapter:
public class RecyclerViewBindingAdapter extends RecyclerView.Adapter<RecyclerViewBindingAdapter.BindingViewHolder> { private Listdata; public RecyclerViewBindingAdapter(List data) { this.data = data; } @Override public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new BindingViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),viewType,parent,false)); } @Override public void onBindViewHolder(BindingViewHolder holder, int position) { AdapterDataItem dataItem = data.get(position); for(Pair idObjectPair: dataItem.idModelPairs){ holder.binding.setVariable(idObjectPair.first, idObjectPair.second); } holder.binding.executePendingBindings(); } @Override public int getItemCount() { return data.size(); } @Override public int getItemViewType(int position) { return data.get(position).layoutId; } public class BindingViewHolder extends RecyclerView.ViewHolder{ ViewDataBinding binding; public BindingViewHolder(ViewDataBinding binding) { super(binding.getRoot()); this.binding=binding; } } }
That's one clean adapter! Notice in the onBindViewHolder() method we dynamically set the variables from our list of AdapterDataItems. Also getItemViewType() returns the layout id in order for us to know which layout to inflate in onCreateViewHolder() method.
Next up lets create some custom attributes for RecyclerView:
@BindingAdapter({"bind:list","bind:layoutManager"}) public static void setList(RecyclerView rv, List dataItems, RecyclerView.LayoutManager layoutManager){ rv.setLayoutManager(layoutManager); rv.setAdapter(new RecyclerViewBindingAdapter(dataItems)); }
Here we define custom attributes to set the :list of models and :layoutManager for our RecyclerView. Now you are all set to use this dynamic adapter with any RecyclerView and any row layouts.
Lets create some layouts for our rows:
This is the layout for a header row.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="groupName" type="String"/> </data> <TextView android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawableLeft="@drawable/ic_group" android:drawablePadding="5dp" android:padding="3dp" android:text="@{groupName}" android:textSize="18sp" android:textStyle="bold" tools:text="Group Name"/> </layout>
This is a layout for item row.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="personModel" type="com.codeprinciples.databindingtricksandmagic.models.Person"/> <variable name="personPresenter" type="com.codeprinciples.databindingtricksandmagic.presenters.PersonPresenter"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:foreground="?selectableItemBackground" android:onClick="@{(v) -> personPresenter.onPersonClicked(personModel)}"> <ImageView android:layout_width="40dp" android:layout_height="30dp" android:src="@drawable/ic_person" android:layout_gravity="center_vertical" android:padding="5dp"/> <TextView android:orientation="vertical" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="First Name:"/> <TextView android:orientation="vertical" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="@{personModel.firstName}" android:textStyle="bold" tools:text="John"/> <TextView android:orientation="vertical" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Last Name:"/> <TextView android:orientation="vertical" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="@{personModel.lastName}" android:textStyle="bold" tools:text="Doe"/> </LinearLayout> </layout>
We will have a PersonPresenter interface handling all the clicks:
public interface PersonPresenter { void onPersonClicked(Person person); }Finally lets create a new layout and new activity:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="modelList" type="java.util.List"/> <variable name="listLayoutManager" type="android.support.v7.widget.RecyclerView.LayoutManager"/> </data> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" app:list="@{modelList}" app:layoutManager="@{listLayoutManager}"/> </layout>
The activity:
public class ListExampleActivity extends AppCompatActivity implements PersonPresenter { private ActivityListExampleBinding mBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle("Dynamic List Bindings Example"); mBinding = DataBindingUtil.setContentView(this, R.layout.activity_list_example); mBinding.setListLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)); mBinding.setModelList(getModelList()); } private List getModelList() { Listitems = new ArrayList<>(); //Heading items.add(new AdapterDataItem(R.layout.layout_item_heading, BR.groupName,"Employees")); //Items items.add(new AdapterDataItem( R.layout.layout_item_info, new Pair (BR.personModel, new Person("Bob","Smith")), new Pair (BR.personPresenter, this))); ...more items... return items; } @Override public void onPersonClicked(Person person) { Intent intent = new Intent(this,PersonDetailsActivity.class); intent.putExtra(PersonDetailsActivity.TAG_PERSON,person); startActivity(intent); } }
In our Activity onCreate() we pass the list of models and the LinearLayoutManager to the binding instance. In getModelList() we created a list of models with header rows and info rows. layout_item_heading.xml binds to a string variable and that variable's id is BR.groupName. BR is a generated class with binding variable ids similar to R class. layout_item_info.xml binds to a Person model and that variable's id is BR.personModel. layout_item_info.xml also takes PersonPresenter for the row's onClick listener. In our case the ListExampleActivity implements PersonPresenter.onPersonClicked() method.
Result:
Conclusion:
As you can see the power of Android' Data Binding library and its potential to simplify and eliminate repetitive tasks in Android developer's everyday life. Hopefully this post was convincing enough for you to start using it in your production applications. What other cool things do you use Data Binding library for? Let me know in the comments bellow!Resources and Further Reading:
- Official Docs
- GitHub project with code for this post
- Getting Started with Android Data Binding in existing project
Nice article!thanks for sharing such great post with us. i studied all your information and it is really good.
ReplyDeleteAndroid Training in Chennai
Android Course in Chennai
JAVA Training in Chennai
Python Training in Chennai
Big data training in chennai
Selenium Training in Chennai
Android Training in Chennai
Android Course in Chennai
Very nice post! You provide a concept is very useful for increasing myself. I am regularly read your blog and keep sharing with us.
ReplyDeleteOracle DBA Training in Chennai
Oracle DBA Course in Chennai
Spark Training in Chennai
Excel Training in Chennai
Corporate Training in Chennai
Tableau Training in Chennai
Oracle Training in Chennai
Oracle Apps DBA Training in Chennai
Oracle DBA Course in Velachery
The blog taught lots of information. Thank you for the information.
ReplyDeleteAndroid Training in Madurai
Android Course in Madurai
Android Courses in madurai
Android Training in Coimbatore
Android Course in Coimbatore
Android Training Institutes in Coimbatore
Such an excellent and interesting blog, do post like this more with more information, This was very useful, Thank you.
ReplyDeleteaviation training in Chennai
cabin crew course in Chennai
diploma in airline and airport management in Chennai
airport ground staff training in Chennai
Aviation Academy in Chennai
air hostess training in Chennai
airport management courses in Chennai
ground staff training in Chennai
Feeling so good to read your information's in the blog. Good job!
ReplyDeleteDOT NET Training in Chennai
.Net training in chennai
Dot Net Training in T Nagar
Html5 Training in Chennai
Html5 Training Institutes in Chennai
QTP Training in Chennai
LoadRunner Training in Chennai
Very informative blog! I liked it and was very helpful for me. Thanks for sharing. Do share more ideas regularly.
ReplyDeleteSpoken English Classes in Chennai
Best Spoken English Classes in Chennai
Spoken English Class in Chennai
Spoken English in Chennai
English Speaking Classes in Mumbai
English Speaking Course in Mumbai
IELTS Coaching in Chennai
IELTS Coaching Centre in Chennai
IELTS Classes in Mumbai
IELTS Coaching in Mumbai
TreasureBox is operated by a group of young, passionate, and ambitious people that are working diligently towards the same goal - make your every dollar count, as we believe you deserve something better.
ReplyDeleteCheck out the best
bike stand nz
sofa bed nz
Great Article. Thank you for sharing! Really an awesome post for every one.
ReplyDeleteProject Centers in Chennai
Java Training in Chennai
Final Year Project Domains for IT
Java Training in Chennai
Thanks for sharing your innovative ideas to our vision. I have read your blog and I gathered some new information through your blog. Your blog is really very informative and unique. Keep posting like this. Awaiting for your further update.If you are looking for any Data science related information, please visit our website Data science training institute in bangalore
ReplyDeleteThanks of sharing this post…Python is the fastest growing language that helps to get your dream job in a developing area. It says every fundamental in a programming, so if you want to become an expertise in python get some training
ReplyDeleteDot Net Training in Chennai | Dot Net Training in anna nagar | Dot Net Training in omr | Dot Net Training in porur | Dot Net Training in tambaram | Dot Net Training in velachery
awesome article,the content has very informative ideas, waiting for the next update...
ReplyDeleteStudy Abroad Consultants in Kerala
study abroad consultants in thrissur
Study Abroad Consultants in Calicut
abroad job consultancy in coimbatore
Abroad Education Consultants in Coimbatore
europe job consultancy in coimbatore
study abroad
study in poland
study in europe
free masters in germany
Such a mind-blowing blog. I am very fascinated with the information.
ReplyDeletearchitecture of selenium
advantages of angular
features of angularjs
validity of aws certification
android 8.0
aws interview questions and answers for freshers pdf
Your article is good to understand, are you interested in designing the mobile app? Our service is helpful to you.
ReplyDeletebest mobile app development company in chennai
flutter app development company in chennai
Android app development company in chennai
Very nice and good article. Thank you for sharing with us.
ReplyDeleteramanichandran novels
muthulakshmi raghavan novels
sashi murali novels
tamil novels
srikala novels
mallika manivannan novels
Much obliged for sharing this brilliant substance. its extremely fascinating. Numerous web journals I see these days don't actually give whatever pulls in others however the manner in which you have plainly clarified everything it's truly awesome. There are loads of posts But your method of Writing is so Good and Knowledgeable. continue to post such helpful data and view my site too...
ReplyDeletehow to make a paper airplane eagle | how to make a boomerang airplane | the eagle paper airplane | best paper airplane design for distance and accuracy | best paper airplanes for distance and speed | what is the best paper airplane design for distance | paper airplane that flies far and straight | nakamura lock paper airplane instructions | paper airplane templates for distance | science behind paper airplanes