Skip to content

Android Bottom Navigation Activity With RecyclerView Data Populated By Retrofit2 and Load images by Glide

This article will describe how to create a bottom activity with three fragment and populated RecyclerView with retrofit and gson. And we'll use Glide for load images in custom list row.

 

GitHub

Here is my project tree

Let's start......

First I'll create a new project by selecting Bottom Navigation Activity or create manually.

 

First add required dependencies to your build.gradle file in app module


apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "info.androidboss.retrofit"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.0'
compile 'com.android.support:design:25.3.0'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
compile 'com.android.support:support-vector-drawable:25.3.0'
// retrofit, gson
compile 'com.google.code.gson:gson:2.7'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
// glide
compile 'com.github.bumptech.glide:glide:3.7.0'
testCompile 'junit:junit:4.12'
compile 'com.android.support:recyclerview-v7:25.3.0'
}

 

I have done it manually . Go to activity_main.xml from res folder and add a FrameLayout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>

</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">

<FrameLayout
android:id="@+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

</LinearLayout>

 

Now create three fragments which will show in MainActivity when you click to the bottom navigation button.

Here I named OneFragment.java

package info.androidboss.retrofit.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

import info.androidboss.retrofit.R;

public class OneFragment extends Fragment {

private OnFragmentInteractionListener listener;
public static OneFragment newInstance() {
return new OneFragment();
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.fragment_one, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);

return view;
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
listener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
listener = null;
}

public interface OnFragmentInteractionListener {
}
}

Now corresponding layout file is fragment_one.xml

<FrameLayout 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">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment One"
android:layout_margin="16dp"/>

</FrameLayout>

 

Here TwoFragment.java

package info.androidboss.retrofit.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import info.androidboss.retrofit.R;

public class TwoFragment extends Fragment {

private OnFragmentInteractionListener listener;

public static TwoFragment newInstance() {
return new TwoFragment();
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_two, container, false);
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
listener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
listener = null;
}

public interface OnFragmentInteractionListener {
}
}

Now corresponding layout file is fragment_two.xml

<FrameLayout 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">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment One"
android:layout_margin="16dp"/>

</FrameLayout>

 

Here ThreeFragment.java

package info.androidboss.retrofit.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import info.androidboss.retrofit.R;

public class ThreeFragment extends Fragment {

private OnFragmentInteractionListener listener;

public static ThreeFragment newInstance() {
return new ThreeFragment();
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_three, container, false);
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
listener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
listener = null;
}

public interface OnFragmentInteractionListener {
}
}

Now corresponding layout file is fragment_three.xml

<FrameLayout 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">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment One"
android:layout_margin="16dp"/>

</FrameLayout>

 

 

Now add BottomNavigation in activity_main.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>

</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">

<FrameLayout
android:id="@+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:menu="@menu/navigation" />

</LinearLayout>

Now Implement BottomNavigation in MainActivity.java

package info.androidboss.retrofit.activity;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;

import info.androidboss.retrofit.R;
import info.androidboss.retrofit.fragment.OneFragment;
import info.androidboss.retrofit.fragment.ThreeFragment;
import info.androidboss.retrofit.fragment.TwoFragment;

public class MainActivity extends AppCompatActivity implements OneFragment.OnFragmentInteractionListener,
TwoFragment.OnFragmentInteractionListener, ThreeFragment.OnFragmentInteractionListener{

private Toolbar toolbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, OneFragment.newInstance());
fragmentTransaction.commit();

toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}

//Change fragments by click nav buttons
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = OneFragment.newInstance();
break;
case R.id.navigation_dashboard:
fragment = TwoFragment.newInstance();
break;
case R.id.navigation_notifications:
fragment = ThreeFragment.newInstance();
break;
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_layout, fragment);
fragmentTransaction.commit();
}
return true;
}

};

}

Now Run The App

Output will be like below images

navigationnavigation

 

After doing these steps successfully now we will call an API which response JSONobject and we will parse it through GSON using Retrofit 2 HTTP client.

JSON format will like :

{
title: "Tangled",
image: "http://api.androidboss.info/movie/images/8.jpg",
rating: 7.9,
releaseYear: 2010,
genre: [
"Action",
"Drama",
"Sci-Fi"
]
}<span style="font-size: 1rem;">

 

Now we'll create a GSON model class for serialize data.

Here Movie.java Model class

package info.androidboss.retrofit.model;

import com.google.gson.annotations.SerializedName;

import java.util.List;

/**
* Created by RIFAN on 22-Mar-17.
*/

public class Movie {

/**
* title : Dawn of the Planet of the Apes
* image : http://api.androidhive.info/json/movies/1.jpg
* rating : 8.3
* releaseYear : 2014
* genre : ["Action","Drama","Sci-Fi"]
*/

@SerializedName("title")
private String title;
@SerializedName("image")
private String image;
@SerializedName("rating")
private String rating;
@SerializedName("releaseYear")
private String releaseYear;
@SerializedName("genre")
private List<String> genre;

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getImage() {
return image;
}

public void setImage(String image) {
this.image = image;
}

public String getRating() {
return rating;
}

public void setRating(String rating) {
this.rating = rating;
}

public String getReleaseYear() {
return releaseYear;
}

public void setReleaseYear(String releaseYear) {
this.releaseYear = releaseYear;
}

public List<String> getGenre() {
return genre;
}

public void setGenre(List<String> genre) {
this.genre = genre;
}

@Override
public String toString() {
return "Movie{" +
"title='" + title + '\'' +
", image='" + image + '\'' +
", rating='" + rating + '\'' +
", releaseYear=" + releaseYear +
", genre=" + genre +
'}';
}
}

 

 

Now create Retrofit API Client.

Here RetroFitApiClient.java class

package info.androidboss.retrofit.utils;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
* Created by RIFAN on 22-Mar-17.
*/

public class RetroFitApiClient {

public static final String BASE_URL = "http://api.androidboss.info/movie/";
private static Retrofit retrofit = null;

public static Retrofit getClient(){
if(retrofit==null){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory
.create()).build();
}
return retrofit;
}
}

 

Now create an interface to get JSON object.

Here is RetroFitApiInterface.java interface

package info.androidboss.retrofit.appinterface;

import java.util.List;

import info.androidboss.retrofit.model.Movie;
import retrofit2.Call;
import retrofit2.http.GET;

/**
* Created by RIFAN on 22-Mar-17.
*/

public interface RetroFitApiInterface {
@GET("movies.json")
Call<List<Movie>> getMovie();
}

 

 

Now create an adapter for recycler list view which extends RecyclerView.Adapter<ViewHolder>

Here is the MovieAdapter.java

package info.androidboss.retrofit.adapter;

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 com.bumptech.glide.Glide;

import java.util.List;

import info.androidboss.retrofit.R;
import info.androidboss.retrofit.model.Movie;

/**
* Created by RIFAN on 22-Mar-17.
*/

public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MyViewHolder> {

List<Movie> movieList;
Context context;

public MovieAdapter(List<Movie> movieList, Context context) {
this.movieList = movieList;
this.context = context;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.custom_list_row, parent, false);

return new MyViewHolder(itemView);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Movie movie = movieList.get(position);

holder.tvTitle.setText(movie.getTitle());
holder.tvYear.setText(movie.getReleaseYear());
holder.tvRating.setText(movie.getRating());
Glide.with(context)
.load(movie.getImage())
.centerCrop()
.into(holder.imageView);

}

@Override
public int getItemCount() {
return movieList.size();
}

@Override
public long getItemId(int position) {
return position;
}

public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView tvTitle;
public TextView tvYear;
public TextView tvRating;
public ImageView imageView;

public MyViewHolder(View view) {
super(view);
tvTitle = (TextView) view.findViewById(R.id.tvTitle);
tvYear = (TextView) view.findViewById(R.id.tvYear);
tvRating = (TextView) view.findViewById(R.id.tvRating);
imageView = (ImageView) view.findViewById(R.id.imageView);
}
}
}

We inflate a custom row layout in adapter class  which is custom_list_row.xml

<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
app:srcCompat="@mipmap/ic_launcher_round"
android:layout_marginLeft="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent" />

<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Movie Title"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="@+id/imageView"
android:layout_marginTop="0dp"
app:layout_constraintLeft_toRightOf="@+id/imageView"
android:layout_marginLeft="17dp" />

<TextView
android:id="@+id/tvYear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Release Year"
android:layout_marginTop="16dp"
android:textSize="12sp"
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
app:layout_constraintLeft_toRightOf="@+id/imageView"
android:layout_marginLeft="17dp" />

<TextView
android:id="@+id/tvRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rating"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/imageView"
android:layout_marginBottom="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>

 

 

Now we'll initialize this adapter in OneFragment.java and load list in RecyclerView .

Here is OneFragment.java

package info.androidboss.retrofit.fragment;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

import info.androidboss.retrofit.model.Movie;
import info.androidboss.retrofit.adapter.MovieAdapter;
import info.androidboss.retrofit.R;
import info.androidboss.retrofit.utils.RetroFitApiClient;
import info.androidboss.retrofit.appinterface.RetroFitApiInterface;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class OneFragment extends Fragment {

MovieAdapter movieAdapter;
RecyclerView recyclerView;
List<Movie> movieList = new ArrayList<Movie>();
private OnFragmentInteractionListener listener;
public static OneFragment newInstance() {
return new OneFragment();
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.fragment_one, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);

movieAdapter = new MovieAdapter(movieList, getActivity());
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), LinearLayoutManager.VERTICAL));
recyclerView.setAdapter(movieAdapter);
getMovieList();
return view;
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
listener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}

@Override
public void onDetach() {
super.onDetach();
listener = null;
}

public void getMovieList() {
RetroFitApiInterface apiInterface = RetroFitApiClient.getClient().create(RetroFitApiInterface.class);
Call<List<Movie>> call = apiInterface.getMovie();
call.enqueue(new Callback<List<Movie>>() {
@Override
public void onResponse(Call<List<Movie>> call, Response<List<Movie>> response) {

if (response==null){
Toast.makeText(getActivity(), "Somthing Went Wrong...!!", Toast.LENGTH_SHORT).show();
}else{
for (Movie movie:response.body()){
movieList.add(movie);
}
Log.i("RESPONSE: ", ""+response.toString());
}
movieAdapter.notifyDataSetChanged();
}

@Override
public void onFailure(Call<List<Movie>> call, Throwable t) {
Toast.makeText(getActivity(), "Unable to fetch json: " + t.getMessage(), Toast.LENGTH_LONG).show();
Log.e("ERROR: ", t.getMessage());
}
});
}

public interface OnFragmentInteractionListener {
}
}

 

Now Add INTERNET permission in AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

 

Now run your app and you will see result like below image

After parse data

Leave a Reply