Read Object List from Web API with Retrofit in Android


On the Eclipse, create a Spring Boot project

Enter Project Information:

  • Name: WebAPIServer
  • Group: com.demo
  • Artifact: WebAPIServer
  • Description: Web API Server
  • Package: com.demo

Select the technologies and libraries to be used:

  • JPA
  • MySQL
  • Web

Click Next button to show Site Information for project

Click Finish button to finish create Spring Boot project




<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.demo</groupId>
	<artifactId>WebAPIServer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>WebAPIServer</name>
	<description>Web API Server</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.3.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Create a database with the name is web_api_server. This database have 1 table: Product table

--
-- Table structure for table `product`
--

CREATE TABLE `product` (
  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(250) NOT NULL,
  `price` double NOT NULL,
  `quantity` int(11) NOT NULL,
  `description` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `product`
--

INSERT INTO `product` (`id`, `name`, `price`, `quantity`, `description`) VALUES
(1, 'Computer 1', 14, 2, 'Description 1'),
(2, 'Computer 2', 5, 7, 'Description 2'),
(3, 'Mobile 1', 7, 4, 'Description 3'),
(4, 'Mobile 2', 11, 8, 'Description 4'),
(5, 'Mobile 3', 7, 9, 'Description 5');

spring.datasource.url= jdbc:mysql://localhost:3306/web_api_server
spring.datasource.username=root
spring.datasource.password=123456

server.port=9596




Create new package named com.demo.entities. In this package, create a entity class – Product.java, to represent the above table

package com.demo.entities;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "product")
public class Product implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	private String name;
	private double price;
	private int quantity;
	private String description;

	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;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getQuantity() {
		return quantity;
	}

	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

}

Create new package named com.demo.repositories. In this package create the ProductRepository interface implements from CrudRepository interface of Spring Data JPA that provides CRUD operations for an entity.

package com.demo.repositories;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.demo.entities.Product;

@Repository("productRepository")
public interface ProductRepository extends CrudRepository<Product, Integer> {

}

The ProductService.java interface contains methods to interact with the database.

package com.demo.services;

import com.demo.entities.Product;

public interface ProductService {

	public Iterable<Product> findAll();

}




The ProductServiceImpl.java class implements methods from ProductService.java interfaces that contains methods to interact with the database.

package com.demo.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.entities.Product;
import com.demo.repositories.ProductRepository;

@Service("productService")
public class ProductServiceImpl implements ProductService {

	@Autowired
	private ProductRepository productRepository;

	@Override
	public Iterable<Product> findAll() {
		return productRepository.findAll();
	}

}

Create new package named com.demo.controllers. In this package, create controller as below:

Create new java class, named ProductController.java

package com.demo.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.demo.entities.Product;
import com.demo.services.ProductService;

@RestController
@RequestMapping("api/product")
public class ProductController {

	@Autowired
	private ProductService productService;

	@RequestMapping(value = "findall",
					method = RequestMethod.GET,
					produces = { MimeTypeUtils.APPLICATION_JSON_VALUE },
					headers = "Accept=application/json")
	public ResponseEntity<Iterable<Product>> findAll() {
		try {
			Iterable<Product> products = productService.findAll();
			return new ResponseEntity<Iterable<Product>>(products, HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<Iterable<Product>>(HttpStatus.BAD_REQUEST);
		}
	}

}

Access Rest API Controller use the following url: http://localhost:9596/api/product/findall

Output

[
	{"id":"1","name":"Computer 1","price":14.0,"quantity":2,"description":"Description 1"},
	{"id":"2","name":"Computer 2","price":5.0,"quantity":7,"description":"Description 2"},
	{"id":"3","name":"Mobile 1","price":7.0,"quantity":4,"description":"Description 3"},
	{"id":"4","name":"Mobile 2","price":11.0,"quantity":8,"description":"Description 4"},
	{"id":"5","name":"Mobile 3","price":7.0,"quantity":9,"description":"Description 5"}
]

Create new project in Android Studio with steps as below:




Open res\values\strings.xml file and add new string as below:

<resources>
    <string name="app_name">Learn Android with Real Apps</string>
    <string name="usd">$</string>
</resources>

Open build.gradle file in Gradle Scripts and add Retrofit libraies as below:

implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'

Open AndroidManifest.xml file in manifest folder, add permissions as below:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.demo.learnandroidwithrealapps">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Create new package named entities. In this package, create new java class named Product.java as below:

package android.demo.entities;

import com.google.gson.annotations.SerializedName;
import java.io.Serializable;

public class Product implements Serializable {

    @SerializedName("id")
    private int id;

    @SerializedName("name")
    private String name;

    @SerializedName("price")
    private double price;

    @SerializedName("quantity")
    private int quantity;

    @SerializedName("description")
    private String description;

    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;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}




Select res\layout folder. In this folder, create new layout named product_row_layout.xml as below:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textViewName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/textViewDescription"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textViewPrice"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Create new package named adapters. In this package, create new java class named ProductListAdapter.java as below:

package android.demo.adapters;

import android.content.Context;
import android.demo.entities.Product;
import android.demo.learnandroidwithrealapps.R;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.util.List;

public class ProductListAdapter extends ArrayAdapter<Product> {

    private List<Product> products;
    private Context context;

    public ProductListAdapter(List<Product> products, Context context) {
        super(context, R.layout.product_row_layout, products);
        this.context = context;
        this.products = products;
    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View view, @NonNull ViewGroup parent) {
        ViewHolder viewHolder;
        if (view == null) {
            viewHolder = new ViewHolder();
            LayoutInflater layoutInflater = LayoutInflater.from(context);
            view = layoutInflater.inflate(R.layout.product_row_layout, parent, false);
            viewHolder.textViewName = view.findViewById(R.id.textViewName);
            viewHolder.textViewPrice = view.findViewById(R.id.textViewPrice);
            viewHolder.textViewDescription = view.findViewById(R.id.textViewDescription);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }
        Product product = products.get(position);
        viewHolder.textViewName.setText(product.getName());
        viewHolder.textViewDescription.setText(product.getDescription());
        viewHolder.textViewPrice.setText(context.getText(R.string.usd) + String.valueOf(product.getPrice()));
        return view;

    }

    private static class ViewHolder {
        public static TextView textViewName;
        public static TextView textViewDescription;
        public static TextView textViewPrice;
    }

}




Create new package named api. In this package, create new api as below:

Create new java class named APIClient.java as below:

package android.demo.services;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class APIClient {

    private static Retrofit retrofit = null;

    public static Retrofit getClient() {

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
        retrofit = new Retrofit.Builder()
								.baseUrl("http://192.168.0.102:9596/api/")
								.addConverterFactory(GsonConverterFactory.create())
								.client(client)
								.build();
        return retrofit;
    }

}

Create new interface named ProductAPI.java as below:

package android.demo.services;

import android.demo.entities.Product;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;

public interface ProductAPI {

    @GET("product/findall")
    Call<List<Product>> findAll();

}

Open res\layout\activity_main.xml file and create layout as below:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ffffff"
    android:orientation="vertical"
    tools:ignore="HardcodedText">

    <ListView
        android:id="@+id/listViewProduct"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Add code to MainActivity.java in android.demo.learnandroidwithrealapps package as below:

package android.demo.learnandroidwithrealapps;

import android.demo.adapters.ProductListAdapter;
import android.demo.entities.Product;
import android.demo.services.APIClient;
import android.demo.services.ProductAPI;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import android.widget.Toast;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

    private ListView listViewProduct;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        loadData();
    }

    private void initView() {
        listViewProduct = findViewById(R.id.listViewProduct);
    }

    private void loadData() {
        ProductAPI productAPI = APIClient.getClient().create(ProductAPI.class);
        productAPI.findAll().enqueue(new Callback<List<Product>>() {
            @Override
            public void onResponse(Call<List<Product>> call, Response<List<Product>> response) {
                try {
                    if (response.isSuccessful()) {
                        List<Product> products = response.body();
                        listViewProduct.setAdapter(new ProductListAdapter(products, getApplicationContext()));
                    } else {
                        Toast.makeText(getApplicationContext(), response.errorBody().string(), Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onFailure(Call<List<Product>> call, Throwable t) {
                Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

}