findViewById()
methods, adding of links to view-elements in Activity
/Fragment
.As I have had some post about this library, through them, you have learned about binding local or online data to your views. In this article, we will look into how to use Data Binding with
RecyclerView
. So lets go ahead and see how it all works.Before start, adding
RecyclerView
and CardView
dependencies and data binding library to your app-level build.gradle:
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "info.devexchanges.databindingrecyclerview"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:recyclerview-v7:24.2.0'
compile 'com.android.support:cardview-v7:24.2.0'
}
Create your POJO class
Country
with 2 variables are id and name for your project:
Country.java
package info.devexchanges.databindingrecyclerview;
public class Country {
private int id;
private String name;
public Country() {
}
public Country(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Defining in XML file
RecyclerView
row, so open your it's layout file and add layout
tag as root of it. It is necessary to have layout
tag and data
tag. It holds information about which POJO is using in layout:
item_recycler_view.xml
As you can see, we'll bind id and name of <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="country"
type="info.devexchanges.databindingrecyclerview.Country" />
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
card_view:cardCornerRadius="2dp"
card_view:contentPadding="10dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:src="@drawable/world"
android:layout_width="80dp"
android:layout_height="80dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/image"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="ID"
android:textSize="22sp" />
<TextView
android:id="@+id/country_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(country.id)}"
android:textSize="22sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="Name"
android:textSize="22sp" />
<TextView
android:id="@+id/country_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{country.name}"
android:textSize="22sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
</layout>
Country
to 2 TextViews
later!
Configuring ViewHolder and RecyclerView adapter
RecyclerView
, we require to create a custom ViewHolder
. Create a new class and name it CountryViewHolder
like this:
CountryViewHolder.java
Here, package info.devexchanges.databindingrecyclerview;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import info.devexchanges.databindingrecyclerview.databinding.ItemRecyclerViewBinding;
public class CountryViewHolder extends RecyclerView.ViewHolder {
private ItemRecyclerViewBinding binding;
public CountryViewHolder(View view) {
super(view);
binding = DataBindingUtil.bind(view);
}
public void bind(Country country) {
binding.setCountry(country);
}
}
ItemRecyclerViewBiding
class is auto-generated by project. When you use data
tag in your layout, Android will auto generate a class with layout filename and a suffix “Binding”. In out case, layout file name is item_recycler_view
so auto-generated class is ItemRecyclerViewBinding
.Create an adapter class for your
RecyclerView
:
RecyclerViewAdapter.java
Here, you just use package info.devexchanges.databindingrecyclerview;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import info.devexchanges.databindingrecyclerview.databinding.ItemRecyclerViewBinding;
public class RecyclerViewAdapter extends RecyclerView.Adapter<CountryViewHolder> {
private List<Country> users;
public RecyclerViewAdapter(List<Country> users) {
this.users = users;
}
@Override
public CountryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View statusContainer = inflater.inflate(R.layout.item_recycler_view, parent, false);
return new CountryViewHolder(statusContainer);
}
@Override
public void onBindViewHolder(CountryViewHolder holder, int position) {
Country status = users.get(position);
holder.bind(status);
}
@Override
public int getItemCount() {
return users.size();
}
}
holder.bind(status);
code, this will actually bind your country
object to your layout. There is nothing complex in this adapter class!
Activity programmatically code
ArrayList
of Country
. The main work of our activity is starting an AsyncTask
and download/parsing data:
MainActivity.java
And this is our custom package info.devexchanges.databindingrecyclerview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ArrayList<Country> countries;
private RecyclerViewAdapter adapter;
private final static String JSON_URL =
"https://gist.githubusercontent.com/DevExchanges/29e8bb477bf520b3c076b1073a9fcd0f/raw/ad8fb0759cebde0e8ed492794ea8cc0bee184bb9/country.json";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
countries = new ArrayList<>();
adapter = new RecyclerViewAdapter(countries);
recyclerView.setAdapter(adapter);
}
@Override
protected void onStart() {
super.onStart();
//Load JSON data from an URL
new GetCountriesFromURLTask(this, JSON_URL).execute();
}
public void parseJsonResponse(String result) {
try {
JSONObject json = new JSONObject(result);
JSONArray jArray = new JSONArray(json.getString("message"));
countries.clear();
for (int i = 0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
Country country = new Country();
country.setId(jObject.getInt("id"));
country.setName(jObject.getString("name"));
countries.add(country);
}
adapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
AsyncTask
:
GetCountriesFromURLTask.java
package info.devexchanges.databindingrecyclerview;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GetCountriesFromURLTask extends AsyncTask<Void, Void, String> {
private MainActivity activity;
private String url;
private ProgressDialog dialog;
public GetCountriesFromURLTask(MainActivity activity, String url) {
super();
this.activity = activity;
this.url = url;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progress dialog
dialog = new ProgressDialog(activity);
dialog.setTitle("Loading");
dialog.setMessage("Loading data from URL...");
dialog.setIndeterminate(false);
dialog.show();
}
@Override
protected String doInBackground(Void... params) {
// call load JSON from url method
return loadJSON(this.url);
}
@Override
protected void onPostExecute(String result) {
activity.parseJsonResponse(result);
dialog.dismiss();
}
public String loadJSON(String url) {
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
return jParser.getJSON(url, 20000);
}
private class JSONParser {
public String getJSON(String url, int timeout) {
HttpURLConnection urlConnection = null;
try {
URL u = new URL(url);
urlConnection = (HttpURLConnection) u.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setRequestProperty("Content-length", "0");
urlConnection.setUseCaches(false);
urlConnection.setAllowUserInteraction(false);
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.connect();
int status = urlConnection.getResponseCode();
switch (status) {
case 200:
case 201:
BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
return sb.toString();
}
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
} finally {
if (urlConnection != null) {
try {
urlConnection.disconnect();
} catch (Exception ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
}
}
return null;
}
}
}
Running application
<uses-permission android:name="android.permission.INTERNET" />
We'll have this output:
Conclusions
RecyclerView
. This is is a powerful tool, I suspect it will become more useful and more widely adopted. For now though, there are a few bugs and some kinks that need to be ironed out. After experimenting with it for a while, I am excited for what the library could potentially do in the future.
Read more:
- Getting started with Data Binding
- Combining Data Binding with Picasso to loading image from URL