Read Simple Values 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.jpa.repository.Query;
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> {

	@Query("select sum(p.quantity) from Product p")
	public long sumQuantities();

	@Query("select sum(p.price * p.quantity) from Product p")
	public double total();

}

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

package com.demo.services;

public interface ProductService {

	public long sumQuantities();

	public double total();

	public boolean exists(int id);

}

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.repositories.ProductRepository;

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

	@Autowired
	private ProductRepository productRepository;

	@Override
	public long sumQuantities() {
		return productRepository.sumQuantities();
	}

	@Override
	public double total() {
		return productRepository.total();
	}

	@Override
	public boolean exists(int id) {
		return productRepository.existsById(id);
	}

}




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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.demo.services.ProductService;

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

	@Autowired
	private ProductService productService;

	@RequestMapping(value = "sumQuantities",
					method = RequestMethod.GET,
					produces = { MimeTypeUtils.TEXT_PLAIN_VALUE })
	public ResponseEntity<String> sumQuantities() {
		try {
			long result = productService.sumQuantities();
			return new ResponseEntity<String>(String.valueOf(result), HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

	@RequestMapping(value = "total",
			method = RequestMethod.GET,
			produces = { MimeTypeUtils.TEXT_PLAIN_VALUE })
	public ResponseEntity<String> total() {
		try {
			double result = productService.total();
			return new ResponseEntity<String>(String.valueOf(result), HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

	@RequestMapping(value = "exists/{id}",
			method = RequestMethod.GET,
			produces = { MimeTypeUtils.TEXT_PLAIN_VALUE })
	public ResponseEntity<String> exists(@PathVariable("id") int id) {
		try {
			boolean result = productService.exists(id);
			return new ResponseEntity<String>(String.valueOf(result), HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
		}
	}

}

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

Output

true

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

Output

242.0

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

Output

30

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>
    <string name="id">Id</string>
    <string name="check_product">Check Product</string>
    <string name="total">Total</string>
    <string name="sum_quantities">Sum Quantities</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 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.api;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface ProductAPI {

    @GET("product/sumQuantities")
    Call<ResponseBody> sumQuantities();

    @GET("product/total")
    Call<ResponseBody> total();

    @GET("product/exists/{id}")
    Call<ResponseBody> exists(@Path("id") int id);

}




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

    <EditText
        android:id="@+id/editTextId"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/id"
        android:inputType="textPersonName" />

    <Button
        android:id="@+id/buttonCheckProduct"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/check_product" />

    <Button
        android:id="@+id/buttonSumQuantities"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/sum_quantities" />

    <Button
        android:id="@+id/buttonTotal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/total" />

</LinearLayout>

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

package android.demo.learnandroidwithrealapps;

import android.demo.api.APIClient;
import android.demo.api.ProductAPI;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

    private EditText editTextId;
    private Button buttonCheckProduct, buttonSumQuantities, buttonTotal;

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

    private void initView() {
        editTextId = findViewById(R.id.editTextId);
        buttonCheckProduct = findViewById(R.id.buttonCheckProduct);
        buttonCheckProduct.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonCheckProduct_onClick(view);
            }
        });
        buttonSumQuantities = findViewById(R.id.buttonSumQuantities);
        buttonSumQuantities.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonSumQuantities_onClick(view);
            }
        });
        buttonTotal = findViewById(R.id.buttonTotal);
        buttonTotal.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonTotal_onClick(view);
            }
        });
    }

    private void buttonTotal_onClick(View view) {
        ProductAPI productAPI = APIClient.getClient().create(ProductAPI.class);
        productAPI.total().enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    if (response.isSuccessful()) {
                        double result = Double.parseDouble(response.body().string());
                        Toast.makeText(getApplicationContext(), getString(R.string.total) + ": " + String.valueOf(result), Toast.LENGTH_LONG).show();
                    } 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<ResponseBody> call, Throwable t) {
                Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

    private void buttonSumQuantities_onClick(View view) {
        ProductAPI productAPI = APIClient.getClient().create(ProductAPI.class);
        productAPI.sumQuantities().enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    if (response.isSuccessful()) {
                        long result = Long.parseLong(response.body().string());
                        Toast.makeText(getApplicationContext(), getString(R.string.sum_quantities) + ": " + String.valueOf(result), Toast.LENGTH_LONG).show();
                    } 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<ResponseBody> call, Throwable t) {
                Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

    private void buttonCheckProduct_onClick(View view) {
        int id = Integer.parseInt(editTextId.getText().toString());
        ProductAPI productAPI = APIClient.getClient().create(ProductAPI.class);
        productAPI.exists(id).enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    if (response.isSuccessful()) {
                        boolean result = Boolean.parseBoolean(response.body().string());
                        Toast.makeText(getApplicationContext(), getString(R.string.check_product) + ": " + String.valueOf(result), Toast.LENGTH_LONG).show();
                    } 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<ResponseBody> call, Throwable t) {
                Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

}