Retrofit http library allows apps to interact with Rest Services. Using Retrofit, one can easily build http get, post, and multipart request components to interact with your application services running on server, meaning building rest clients is easy with Retrofit. Because of its ease of use, this is one of the widely used frameworks in android applications.
Retrofit is not an http client library like apache http client, OkHttp, and HttpUrlConnection. But Retrofit uses http client library and provides type-safe api for apps to interact with Rest Services. By default Retrofit uses OkHttp library as http client.
Retrofit is a type-safe library because it takes care of serialization, deserialization, concurrency and response handling. Retrofit functionality can extended to make it work with libraries like RxJava and Java8 with adapters. Retrofit supports easy plugging capability for converters and adapters.
Retrofit is similar to the other networking library called volley.
Add below libraries to your project to use retrofit and gson converter. OkHttp is part of retrofit latest version so no need to add it separately to gradle build properties file.
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.squareup.retrofit2:converter-gson'
Below are the steps to create retrofit service client and use it to get response from server.
public interface CouponApi {
@GET("coupons/")
Call<CouponsWrapper> getCoupons(@Query("status") String status);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
CouponApi couponService = retrofit.create(CouponApi.class);
Call<CouponsWrapper> call = couponService.getCoupons("latest");
Response<CouponsWrapper> rp = call.execute();
return rp.body();
To make retrofit convert the responses it receives from server, from different formats to java objects and from java objects to other formats which services take as input, you need to add converters to retrofit. For example, to convert json response to your java model object or java model object to Json, you need to add gson converter to retrofit.
Retrofit provides converters for various serialization libraries like gson, jacson, moshi and simple xml.
Converter can be added by calling addConverterFactory method on Retrofit.Builder object.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://...")
.addConverterFactory(GsonConverterFactory.create())
.build();
You can plug adapters to retrofit to make retrofit workable with other libraries like RxJava, Guva and Java 8. Retrofit services can return types from other libraries with adapters. For example, to make retrofit service return object types from RxJava, you need to add RxJava adapter as shown below.
You can add adapters to retrofit by calling addCallAdapterFactory method on Retrofit.Builder class.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http//...")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
Observable<Coupons> latestCoupons = couponService.getCoupons("latest");
To send a get request using retrofit, you need to define the method in your api interface with GET annotation as shown below.
@GET("coupons/")
Call<CouponsWrapper> getCoupons();
To pass query string with http get request using retrofit, annotate input parameter with QUERY. You can define parameter name by passing it to QUERY annotation.
@GET("coupons/")
Call<CouponsWrapper> getCoupons(@Query("status") String status);
You can create dynamic URLs with retrofit using {} in the path and PATH annotation.
@GET("coupon/{store}")
Call<CouponsWrapper> getCoupons(@Path("store") String storename);
To send post request with parameters and their values like submitting an html forms, you need to annotate the method with @FormUrlEncoded and @POST and annotate each parameter you want to send in the post request with @Field.
@FormUrlEncoded
@POST("coupons/")
Call<CouponsWrapper> getCoupons(@Field("store") String storeName, @Field("category") String category);
To send Json request to server, annotate method with POST and annotate input java object which contains json data with Body annotation as shown below. In order for this to work, you need to add gson converter, retrofit uses this to convert java object annotated as body to Json string which will be sent to server as request body.
@POST("add/coupons")
Call<String> loadCoupons(@Body Coupons);
To define api which sends multipart data to server, for example image and title of image, you need to annotate the api method with @Multipart and @PUT, and annotate parts with @Part annotation.
@Multipart
@PUR("uploadCoupons/")
Call<String> uploadCoupons(@Part("xml") RequestBody couponXml, @Part("date") RequestBody date);
As mentioned before, http request can be sent to server synchronously (on the main thread) by calling execute method or asynchronously (on worker thread) by calling enqueue method on the Call object passing Callback object which handles response and error.
call.enqueue(new Callback<CouponsWrapper>() {
@Override
public void onResponse(Call<CouponsWrapper> call, Response<CouponsWrapper> response) {
response.body().getCouponList();
Log.d(TAG, "got response from service using retrofit, performing further processing");
}
@Override
public void onFailure(Call<CouponsWrapper> call, Throwable t) {
Log.e(TAG, "error in getting response from service using retrofit");
}
});
Headers can be added to request by annotating your api method with Headers annotation.
@Headers({"Cache-Control: max-age=200000", "Authorization: askjfaks"})
@GET("coupons/")
Call<CouponsWrapper> getCoupons(@Query("status") String status);
Now, I am going to show how to use retrofit in android with complete example. For this, I am going to use one screen from coupons app. This screen uses coupon app’s rest service and displays list of coupons in recycler view using grid layout manager and custom recycler view item decorator.
Here the call to service and parsing of JSON response is done using retrofit and gson converter.
package com.zoftino.androidui;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface CouponApi {
@GET("coupons/")
Call<CouponsWrapper> getCoupons(@Query("status") String status);
}
package com.zoftino.androidui;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class CouponClient {
public static final String BASE_URL = "http://www.zoftino.com/api/";
private static Retrofit retrofit = null;
public static Retrofit getCouponClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
package com.zoftino.androidui;
public class Coupon {
private String store;
private String coupon;
private String expiryDate;
private String couponCode;
public String getStore() {
return store;
}
public void setStore(String store) {
this.store = store;
}
public String getCoupon() {
return coupon;
}
public void setCoupon(String coupon) {
this.coupon = coupon;
}
public String getExpiryDate() {
return expiryDate;
}
public void setExpiryDate(String expiryDate) {
this.expiryDate = expiryDate;
}
public String getCouponCode() {
return couponCode;
}
public void setCouponCode(String couponCode) {
this.couponCode = couponCode;
}
}
package com.zoftino.androidui;
import android.content.Context;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.io.IOException;
import java.util.List;
import retrofit2.Call;
import retrofit2.Response;
public class ActivityRetrofit extends AppCompatActivity {
private String TAG = ActivityRetrofit.class.getSimpleName();
private RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recylcer_grid);
Log.d(TAG, "set retrofit example layout");
rv = (RecyclerView) findViewById(R.id.store_rv);
GridLayoutManager gridlm = new GridLayoutManager(this, 2);
gridlm.setOrientation(GridLayoutManager.VERTICAL);
gridlm.setSpanCount(2);
rv.setLayoutManager(gridlm);
BoundaryItemDecoration bid = new BoundaryItemDecoration(this, Color.DKGRAY, 4);
rv.addItemDecoration(bid);
Log.d(TAG, "set retrofit recycler view and start asynctask");
new ActivityRetrofit.RetrofitAyncTask().execute(this);
}
private class RetrofitAyncTask extends AsyncTask<Context, Void, List<Coupon>> {
private String TAG = ActivityRetrofit.RetrofitAyncTask.class.getSimpleName();
private Context contx;
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected List<Coupon> doInBackground(Context... params) {
Log.e(TAG, "processing http request in async task using retrofit");
contx = (Context) params[0];
//create service which is implementation of CouponApi interface by passing it to retrofit object
CouponApi couponService = CouponClient.getCouponClient().create(CouponApi.class);
//call api method which returns call object
Call<CouponsWrapper> call = couponService.getCoupons("latest");
try {
//call the api synchronously as this is part of back ground thread already with AsncTask
Response<CouponsWrapper> rp = call.execute();
return rp.body().getCouponList();
} catch (IOException e) {
Log.e(TAG, "error in getting response from service using retrofit");
}
return null;
}
@Override
protected void onPostExecute(List<Coupon> result) {
super.onPostExecute(result);
if (result != null) {
Log.e(TAG, "populate recyclerview grid in UI after response from service using retrofit");
//populate recyclerview grid from retrofit response result
CouponsRecyclerViewGridAdapter rvadapter = new CouponsRecyclerViewGridAdapter(result,contx);
rv.setAdapter(rvadapter);
}
}
}
}
package com.zoftino.androidui;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class CouponsRecyclerViewGridAdapter extends RecyclerView.Adapter<CouponsRecyclerViewGridAdapter.ViewHolder> {
private List<Coupon> couponsList;
private Context context;
public CouponsRecyclerViewGridAdapter(List<Coupon> cLst, Context ctx) {
couponsList = cLst;
context = ctx;
}
@Override
public CouponsRecyclerViewGridAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.retrofitgriditem, parent, false);
CouponsRecyclerViewGridAdapter.ViewHolder viewHolder = new CouponsRecyclerViewGridAdapter.ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(CouponsRecyclerViewGridAdapter.ViewHolder holder, int position) {
Coupon coupon = couponsList.get(position);
holder.couponTv.setText(coupon.getCoupon());
holder.expiryDateTv.setText(coupon.getExpiryDate());
holder.couponCodeTv.setText(coupon.getCouponCode());
int id = context.getResources().getIdentifier(coupon.getStore(), "drawable", context.getPackageName());
holder.storeImg.setImageResource(id);
}
@Override
public int getItemCount() {
return couponsList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView couponTv;
public TextView expiryDateTv;
public TextView couponCodeTv;
public ImageView storeImg;
public ViewHolder(View view) {
super(view);
couponTv = (TextView) view.findViewById(R.id.coupon_t);
expiryDateTv = (TextView) view.findViewById(R.id.expiry_dt_t);
couponCodeTv = (TextView) view.findViewById(R.id.coupon_code_t);
storeImg = (ImageView) view.findViewById(R.id.store_i);
view.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Toast.makeText(context, "You clicked coupons at "+ getAdapterPosition(),
Toast.LENGTH_LONG).show();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp">
<ImageView
android:id="@+id/store_i"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/bestbuy"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"></ImageView>
<TextView
android:id="@+id/coupon_t"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/store_i"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"></TextView>
<TextView
android:id="@+id/coupon_exp_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expiry"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/coupon_t"></TextView>
<TextView
android:id="@+id/expiry_dt_t"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@+id/coupon_exp_txt"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/coupon_t"
app:layout_constraintHorizontal_bias="0.278"></TextView>
<TextView
android:id="@+id/coupon_code_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Coupon Code"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/coupon_exp_txt"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"></TextView>
<TextView
android:id="@+id/coupon_code_t"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/coupon_exp_txt"
app:layout_constraintLeft_toRightOf="@+id/coupon_code_text"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.278"></TextView>
</android.support.constraint.ConstraintLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/store_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</LinearLayout>