Fetch data
For fetching data, we will use popular HTTP-Client retrofit
. Firstly, we are going to create an interface for our API. Create a new package api
and then create a new Interface class CupcakeApi
.
public interface CupcakeApi {
@GET("api/v1/cupcakes/")
Call<CupcakeResponse[]> getCupcakesList(@Query("format") String format);
}
api/v1/cupcakes/
is the api end point- @Query("format") is the get parameter. In our case we will use
json
Create another class CupcakeResponse
for response object.
public class CupcakeResponse {
public String name;
public float rating;
public String price;
public String writer;
public String image;
public String createdAt;
}
A sample response from api end-point will be as follows:
[
{
"name": "Another Chocolate",
"rating": 5,
"price": "5",
"image": "/media/images/cakes/chocolate_cupcake_AjwFoHt.jpg",
"writer": "user2",
"createdAt": "2016-08-04T04:38:36.193330Z"
},
{
"name": "Green Tea Cupcake",
"rating": 4,
"price": "4",
"image": "/media/images/cakes/cup_cake_2.jpg",
"writer": "admin",
"createdAt": "2016-08-01T03:19:29.333117Z"
}
]
Let's implement the retrofit api call in ItemListActivity
. Create a new function initiateCupcakeApi(final view recycleview)
and add the following code.
public static final String API_URL_PROD = "https://djangocupcakeshop.azurewebsites.net";
private void initiateCupcakeApi(final View recyclerView) {
Log.d(LOG_TAG,"initiateCupcakeApi");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL_PROD)
.addConverterFactory(GsonConverterFactory.create())
.build();
CupcakeApi api = retrofit.create(CupcakeApi.class);
Call<CupcakeResponse[]> call = api.getCupcakesList("json");
call.enqueue(new Callback<CupcakeResponse[]>() {
@Override
public void onResponse(Call<CupcakeResponse[]> call, Response<CupcakeResponse[]> response) {
if (response.isSuccessful()) {
Log.d(LOG_TAG, "success - response is " + response.body());
} else {
Log.d(LOG_TAG, "failure response is " + response.raw().toString());
}
}
@Override
public void onFailure(Call<CupcakeResponse[]> call, Throwable t) {
Log.e(LOG_TAG, " Error : " + t.getMessage());
}
});
}
Call initiateCupcakeApi
in onCreate()
method of your activity. You will notice that it will throw an exception because we didn't add INTERNET
permissions in manifest. Open AndroidManifest.xml
and add following code just before the opening application tag.
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Run your application and see Logcat for response logs.
Sava Data
Until now we are fetching the data everytime our activity is created. Fetching data from network is an expensive operation and should not be called frequently. We will use Realm
database to store.
Configuring Realm
Declare folling global variables in ItemListActivity
private RealmConfiguration mRealmConfig;
private Realm mRealm;
and in onCreate
method initialize Realm.
mRealmConfig = new RealmConfiguration.Builder(this).build();
Realm.setDefaultConfiguration(mRealmConfig);
mRealm = Realm.getDefaultInstance();
We are all set to use Realm. Create a new package and name it model
. Create a new java file Cupcake
with following contents.
public class Cupcake extends RealmObject {
public String name;
public String price;
public float rating;
public String image;
public String writer;
public String createdAt;
// Let your IDE generate getters and setters for you!
// Or if you like you can even have public fields and no accessors!
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public float getRating() {
return rating;
}
public void setRating(float rating) {
this.rating = rating;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getWriter() {
return writer;
}
public void setWritere(String writer) {
this.writer = writer;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
}
RealmObject is a special object which stores information related to one Cupcake.
Next step is to save data as soon as we fetch it from Network. Create a new function executeRealmWriteTransaction
with following content.
private void executeRealmWriteTransaction (final List<CupcakeResponse> cupcakeList) {
Log.d(LOG_TAG,"saveRealmObjects : " + cupcakeList.size());
mRealm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
for (int i = 0; i < cupcakeList.size(); i++) {
Cupcake cake = realm.createObject(Cupcake.class);
cake.setName(cupcakeList.get(i).name);
cake.setRating(cupcakeList.get(i).rating);
cake.setPrice(cupcakeList.get(i).price);
cake.setImage(cupcakeList.get(i).image);
cake.setWritere(cupcakeList.get(i).writer);
cake.setCreatedAt(cupcakeList.get(i).createdAt);
}
}
},new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
Log.d(LOG_TAG,"savedRealmObjects");
}
},new Realm.Transaction.OnError(){
@Override
public void onError(Throwable error) {
Log.d(LOG_TAG,"error while writing to realm db :" + error.getMessage());
}
});
}
We are giving a List of Cupcake responses, and saving Realm objects in execute method. You can verify the result by executing a realm query as follows
private RealmResults<Cupcake> getRealmResults() {
RealmResults<Cupcake> sortedCakes = mRealm.where(Cupcake.class).findAllSorted("rating", Sort.DESCENDING);
Log.d(LOG_TAG,"getRealmResults : " + sortedCakes.size());
return sortedCakes;
}
We will create another useful function for deleting Realm objects. We are going to use this function in next lesson.
private void deleteRealmObjects() {
mRealm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.delete(Cupcake.class);
}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
Log.d(LOG_TAG,"realm objects deleted");
initiateCupcakeApi(recyclerView);
}
});
}
Until now, we are done with Fetch and Sava data part. Let's move to next part where will work on UI of the app.