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.
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.
<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>
[/xml]
Now create three fragments which will show in MainActivity
when you click to the bottom navigation button.
Here I named OneFragment.java
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 {
}
}
[/java]
Now corresponding layout file is fragment_one.xml
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>
[/xml]
Here TwoFragment.java
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 {
}
}
[/java]
Now corresponding layout file is fragment_two.xml
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>
[/xml]
Here ThreeFragment.java
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 {
}
}
[/java]
Now corresponding layout file is fragment_three.xml
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>
[/xml]
Now add BottomNavigation
in activity_main.xml
.
<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>
[/xml]
Now Implement BottomNavigation
in MainActivity.java
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;
}
};
}
[/java]
Now Run The App
Output will be like below images
After doing these steps successfully now we will call an API which response JSON
object 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"
] }[/json]
Now we'll create a GSON
model class for serialize data.
Here Movie.java
Model class
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 +
'}';
}
}
[/java]
Now create Retrofit API Client.
Here RetroFitApiClient.java
class
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;
}
}
[/java]
Now create an
interface
to getJSON
object.
Here is RetroFitApiInterface.java
interface
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();
}
[/java]
Now create an adapter for recycler list view which extends
RecyclerView.Adapter<ViewHolder>
Here is the MovieAdapter.java
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);
}
}
}
[/java]
We inflate a custom row layout in adapter class which is custom_list_row.xml
<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>
[/xml]
Now we'll initialize this adapter in
OneFragment.java
and load list inRecyclerView
.
Here is OneFragment.java
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 {
}
}
[/java]
Now Add INTERNET
permission in AndroidManifest.xml
[/xml]
Now run your app and you will see result like below image