Welcome to Retrofit Android Tutorial guys. Today we will learn to build a simple application in android using Retrofit Android Library and SLIM PHP Framework.
Today, we will be covering a lot of things. We will see user registration, user login, session management and many more things. So keep reading carefully as this is going to be a long tutorial.
Table of Contents
Retrofit Android Tutorial – Complete Video Series
- If you want a complete explanation about building API with PHP and SLIM and using them in Android with Retrofit then you should watch this Play List. (Don’t forget to share with your friends).Â
The App Overview
- So lets first understand what we are going to build. The below diagram will explain you in detail.
- As you can see in the above diagram we are going to build a very simple application. Where the registered user can send messages to each other.
- Now the next step is designing the database. I am going to use MySQL for this.
Database Design
- This is our database model.
- It is very simple and to create the above database just go to phpmyadmin create a database and run the following SQL code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
-- Created by Simplified Coding -- tables -- Table: messages CREATE TABLE messages ( id int NOT NULL AUTO_INCREMENT, from_users_id int NOT NULL, to_users_id int NOT NULL, title varchar(100) NOT NULL, message varchar(1000) NOT NULL, sentat timestamp NOT NULL, CONSTRAINT messages_pk PRIMARY KEY (id) ); -- Table: users CREATE TABLE users ( id int NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, email varchar(100) NOT NULL, password text NOT NULL, gender varchar(6) NOT NULL, CONSTRAINT users_pk PRIMARY KEY (id) ); -- foreign keys -- Reference: messages_users_from (table: messages) ALTER TABLE messages ADD CONSTRAINT messages_users_from FOREIGN KEY messages_users_from (to_users_id) REFERENCES users (id); -- Reference: messages_users_to (table: messages) ALTER TABLE messages ADD CONSTRAINT messages_users_to FOREIGN KEY messages_users_to (from_users_id) REFERENCES users (id); -- End of file. |
- Now lets create the REST API.
Building RESTful API using SLIM
Creating Project
- First go to xampp/htdocs and open terminal here. (if you are using windows go to c:/xampp/htdocs in command prompt).
- Now run the following command to create a new project. (Make sure you have composer installed).
1 2 3 |
composer create-project slim/slim-skeleton RetrofitExample |
- In the above line RetrofitExample is the project name. You can change it with whatever you want.
- After executing the above command your php project will be created. Now you can use any Text Editor to work on this project. I am using PHPStorm.
- You will see the following directory structure in the project you just created.
- Open index.php and delete everything that is inside.
- Now inside RetrofitExample (Your project directory) create one more directory named includes.
Defining Constants
- Inside includes create a new php file named Constants.php it will store all the required constants. Make sure to change the database name according to your database in the below script.
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php define('DB_USERNAME', 'root'); define('DB_PASSWORD', ''); define('DB_HOST', 'localhost'); define('DB_NAME', 'retrofit'); define('USER_CREATED', 101); define('USER_EXIST', 102); define('USER_CREATION_FAILED', 103); |
Connecting with Database
- Now in the same directory create one more php file named DbConnect.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php class DbConnect { //Variable to store database link private $con; //Class constructor function __construct() { } //This method will connect to the database function connect() { //Including the constants.php file to get the database constants include_once dirname(__FILE__) . '/Constants.php'; //connecting to mysql database $this->con = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); //Checking if any error occured while connecting if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); return null; } //finally returning the connection link return $this->con; } } |
- The above script will connect with the MySQL database.
Performing Database Operation
- Now create one more php script named DbOperation.php that will perform all the required database operations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
<?php class DbOperation { private $con; function __construct() { require_once dirname(__FILE__) . '/DbConnect.php'; $db = new DbConnect(); $this->con = $db->connect(); } //Method to create a new user function registerUser($name, $email, $pass, $gender) { if (!$this->isUserExist($email)) { $password = md5($pass); $stmt = $this->con->prepare("INSERT INTO users (name, email, password, gender) VALUES (?, ?, ?, ?)"); $stmt->bind_param("ssss", $name, $email, $password, $gender); if ($stmt->execute()) return USER_CREATED; return USER_CREATION_FAILED; } return USER_EXIST; } //Method for user login function userLogin($email, $pass) { $password = md5($pass); $stmt = $this->con->prepare("SELECT id FROM users WHERE email = ? AND password = ?"); $stmt->bind_param("ss", $email, $password); $stmt->execute(); $stmt->store_result(); return $stmt->num_rows > 0; } //Method to send a message to another user function sendMessage($from, $to, $title, $message) { $stmt = $this->con->prepare("INSERT INTO messages (from_users_id, to_users_id, title, message) VALUES (?, ?, ?, ?);"); $stmt->bind_param("iiss", $from, $to, $title, $message); if ($stmt->execute()) return true; return false; } //Method to update profile of user function updateProfile($id, $name, $email, $pass, $gender) { $password = md5($pass); $stmt = $this->con->prepare("UPDATE users SET name = ?, email = ?, password = ?, gender = ? WHERE id = ?"); $stmt->bind_param("ssssi", $name, $email, $password, $gender, $id); if ($stmt->execute()) return true; return false; } //Method to get messages of a particular user function getMessages($userid) { $stmt = $this->con->prepare("SELECT messages.id, (SELECT users.name FROM users WHERE users.id = messages.from_users_id) as `from`, (SELECT users.name FROM users WHERE users.id = messages.to_users_id) as `to`, messages.title, messages.message, messages.sentat FROM messages WHERE messages.to_users_id = ?;"); $stmt->bind_param("i", $userid); $stmt->execute(); $stmt->bind_result($id, $from, $to, $title, $message, $sent); $messages = array(); while ($stmt->fetch()) { $temp = array(); $temp['id'] = $id; $temp['from'] = $from; $temp['to'] = $to; $temp['title'] = $title; $temp['message'] = $message; $temp['sent'] = $sent; array_push($messages, $temp); } return $messages; } //Method to get user by email function getUserByEmail($email) { $stmt = $this->con->prepare("SELECT id, name, email, gender FROM users WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $stmt->bind_result($id, $name, $email, $gender); $stmt->fetch(); $user = array(); $user['id'] = $id; $user['name'] = $name; $user['email'] = $email; $user['gender'] = $gender; return $user; } //Method to get all users function getAllUsers(){ $stmt = $this->con->prepare("SELECT id, name, email, gender FROM users"); $stmt->execute(); $stmt->bind_result($id, $name, $email, $gender); $users = array(); while($stmt->fetch()){ $temp = array(); $temp['id'] = $id; $temp['name'] = $name; $temp['email'] = $email; $temp['gender'] = $gender; array_push($users, $temp); } return $users; } //Method to check if email already exist function isUserExist($email) { $stmt = $this->con->prepare("SELECT id FROM users WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $stmt->store_result(); return $stmt->num_rows > 0; } } |
Handling API Calls
- Now come inside index.php that is inside the public folder and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
<?php use \Psr\Http\Message\ServerRequestInterface as Request; use \Psr\Http\Message\ResponseInterface as Response; require '../vendor/autoload.php'; require_once '../includes/DbOperation.php'; //Creating a new app with the config to show errors $app = new \Slim\App([ 'settings' => [ 'displayErrorDetails' => true ] ]); //registering a new user $app->post('/register', function (Request $request, Response $response) { if (isTheseParametersAvailable(array('name', 'email', 'password', 'gender'))) { $requestData = $request->getParsedBody(); $name = $requestData['name']; $email = $requestData['email']; $password = $requestData['password']; $gender = $requestData['gender']; $db = new DbOperation(); $responseData = array(); $result = $db->registerUser($name, $email, $password, $gender); if ($result == USER_CREATED) { $responseData['error'] = false; $responseData['message'] = 'Registered successfully'; $responseData['user'] = $db->getUserByEmail($email); } elseif ($result == USER_CREATION_FAILED) { $responseData['error'] = true; $responseData['message'] = 'Some error occurred'; } elseif ($result == USER_EXIST) { $responseData['error'] = true; $responseData['message'] = 'This email already exist, please login'; } $response->getBody()->write(json_encode($responseData)); } }); //user login route $app->post('/login', function (Request $request, Response $response) { if (isTheseParametersAvailable(array('email', 'password'))) { $requestData = $request->getParsedBody(); $email = $requestData['email']; $password = $requestData['password']; $db = new DbOperation(); $responseData = array(); if ($db->userLogin($email, $password)) { $responseData['error'] = false; $responseData['user'] = $db->getUserByEmail($email); } else { $responseData['error'] = true; $responseData['message'] = 'Invalid email or password'; } $response->getBody()->write(json_encode($responseData)); } }); //getting all users $app->get('/users', function (Request $request, Response $response) { $db = new DbOperation(); $users = $db->getAllUsers(); $response->getBody()->write(json_encode(array("users" => $users))); }); //getting messages for a user $app->get('/messages/{id}', function (Request $request, Response $response) { $userid = $request->getAttribute('id'); $db = new DbOperation(); $messages = $db->getMessages($userid); $response->getBody()->write(json_encode(array("messages" => $messages))); }); //updating a user $app->post('/update/{id}', function (Request $request, Response $response) { if (isTheseParametersAvailable(array('name', 'email', 'password', 'gender'))) { $id = $request->getAttribute('id'); $requestData = $request->getParsedBody(); $name = $requestData['name']; $email = $requestData['email']; $password = $requestData['password']; $gender = $requestData['gender']; $db = new DbOperation(); $responseData = array(); if ($db->updateProfile($id, $name, $email, $password, $gender)) { $responseData['error'] = false; $responseData['message'] = 'Updated successfully'; $responseData['user'] = $db->getUserByEmail($email); } else { $responseData['error'] = true; $responseData['message'] = 'Not updated'; } $response->getBody()->write(json_encode($responseData)); } }); //sending message to user $app->post('/sendmessage', function (Request $request, Response $response) { if (isTheseParametersAvailable(array('from', 'to', 'title', 'message'))) { $requestData = $request->getParsedBody(); $from = $requestData['from']; $to = $requestData['to']; $title = $requestData['title']; $message = $requestData['message']; $db = new DbOperation(); $responseData = array(); if ($db->sendMessage($from, $to, $title, $message)) { $responseData['error'] = false; $responseData['message'] = 'Message sent successfully'; } else { $responseData['error'] = true; $responseData['message'] = 'Could not send message'; } $response->getBody()->write(json_encode($responseData)); } }); //function to check parameters function isTheseParametersAvailable($required_fields) { $error = false; $error_fields = ""; $request_params = $_REQUEST; foreach ($required_fields as $field) { if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) { $error = true; $error_fields .= $field . ', '; } } if ($error) { $response = array(); $response["error"] = true; $response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty'; echo json_encode($response); return false; } return true; } $app->run(); |
- The API Building is finished. I haven’t explain this part too much as we already did it in one of the previous tutorials about PHP Restful API using SLIM.
Testing the APIs
- Now lets test the APIs. For testing I am using Postman you can use any REST Client. So the URLs we have are.
URL | Method | Parameters |
http://localhost/RetrofitExample/public/register | POST | name, email, password, gender |
http://localhost/RetrofitExample/public/login | POST | email, password |
http://localhost/RetrofitExample/public/messages/{id} | GET | |
http://localhost/RetrofitExample/public/update/{id} | POST | name, email, password, gender |
http://localhost/RetrofitExample/public/sendmessage | POST | from, to, title, message |
http://localhost/RetrofitExample/public/users | GET |
http://localhost/RetrofitExample/public/register
- The same way you can test all the URLs and then we can start developing the Android Application.
Building Android Application using Retrofit
Creating Project
- Create a new Android Studio Project. I created a project named RetrofitExample.
- Once your project is loaded go to app level build.gradle file and add the following dependencies.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) 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:24.2.1' testCompile 'junit:junit:4.12' //add the following dependencies compile 'com.squareup.retrofit2:retrofit:2.2.0' compile 'com.squareup.retrofit2:converter-gson:2.2.0' } |
- Now sync your project with gradle and Retrofit and Gson is added.
Designing Screens
First Screen
- So our first screen is having two buttons for Sign In or Sign Up. So inside activity_main.xml paste the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="net.simplifiedcoding.retrofitexample.activities.MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@mipmap/ic_launcher" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal"> <Button android:id="@+id/buttonSignIn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Sign In" /> <Button android:id="@+id/buttonSignUp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="Sign Up" /> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/imageView" android:layout_alignParentStart="true" android:text="Simplified Coding" android:textAlignment="center" android:textAppearance="@style/Base.TextAppearance.AppCompat.Large" /> </RelativeLayout> |
- The above code will generate the following layout.
- This is screen is very simple, having only two buttons that will take us to the respective screens.
Sign In Screen
- Now create a new Empty Activity named SignInActivity and inside the layout file of this activity write the following xml code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_sign_in" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="net.simplifiedcoding.retrofitexample.activities.SignInActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical"> <EditText android:id="@+id/editTextEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter email " android:inputType="textEmailAddress" /> <EditText android:id="@+id/editTextPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter password " android:inputType="textPassword" /> <Button android:id="@+id/buttonSignIn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Sign In" /> </LinearLayout> </RelativeLayout> |
- This screen will look like as below.
Sign Up Screen
- Now again create a new Empty Activity for Sign Up Screen and write the following xml code in the layout file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_sign_up" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="net.simplifiedcoding.retrofitexample.activities.SignUpActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical"> <EditText android:id="@+id/editTextName" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter name " android:inputType="text" /> <EditText android:id="@+id/editTextEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter email " android:inputType="textEmailAddress" /> <EditText android:id="@+id/editTextPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter password " android:inputType="textPassword" /> <RadioGroup android:id="@+id/radioGender" android:layout_width="match_parent" android:layout_height="wrap_content"> <RadioButton android:id="@+id/radioMale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Male" /> <RadioButton android:id="@+id/radioFemale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Female" /> </RadioGroup> <Button android:id="@+id/buttonSignIn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Sign Up" /> </LinearLayout> </RelativeLayout> |
- This screen will look like as below.
Home Screen
- User will come to this screen after Signing In. This will be a Navigation Drawer Activity. So create a Navigation Drawer Activity for the Home Screen.
- Creating a Navigation drawer activity will create a number of layout files inside the layout directory. First come to nav_header_home.xml and modify it as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?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" android:layout_width="match_parent" android:layout_height="@dimen/nav_header_height" android:background="@drawable/side_nav_bar" android:gravity="bottom" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <TextView android:id="@+id/textViewName" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:text="Android Studio" android:textAppearance="@style/TextAppearance.AppCompat.Large" /> </LinearLayout> |
- Now open app_bar_home.xml and remove the floating action button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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="match_parent" android:fitsSystemWindows="true" tools:context="net.simplifiedcoding.retrofitexample.activities.HomeActivity"> <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> <include layout="@layout/content_home" /> </android.support.design.widget.CoordinatorLayout> |
- Now go to menu folder and you will see activity_home_drawer.xml change it to the following.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/nav_home" android:title="Home" /> <item android:id="@+id/nav_profile" android:title="Profile" /> <item android:id="@+id/nav_messages" android:title="Messages" /> <item android:id="@+id/nav_logout" android:title="Logout" /> </group> </menu> |
- Now we will display all the remaining screen inside this home screen using fragments. So lets quickly design the layout for all other screens.
Designing Home Fragment
- As we decided in the app that in the home screen we will display all users. For this we will use RecyclerView and CardView. So first you need to add RecyclerView and CardView in your project. For this go to project structure->app->dependencies and add library dependency with CardView and RecyclerView. For details you can check this RecyclerView tutorial.
- Create a new layout file named fragment_home.xml and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?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"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerViewUsers" android:layout_width="match_parent" android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView> </LinearLayout> |
- As you can see we have a RecyclerView in fragment_home, so we need to create one more layout for the RecyclerView. So create a new layout file named list_users.xml and we will display all the users of the application in the list.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<?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="wrap_content" android:orientation="vertical"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="4dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp"> <TextView android:id="@+id/textViewName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="2" android:text="Belal Khan" android:textAppearance="@style/Base.TextAppearance.AppCompat.Large" /> <ImageButton android:id="@+id/imageButtonMessage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/icon_message" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> |
- Now in this screen we will also have an alert dialog to send messages to the users. We will also design this dialog.
Designing Alert Message Dialog
- Create a file named dialog_send_message.xml and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:padding="@dimen/activity_horizontal_margin" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/editTextTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter title" /> <EditText android:id="@+id/editTextMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter Message" android:lines="7" /> </LinearLayout> |
- Now lets design the profile fragment screen.
Designing Profile Fragment
- Again create a new layout file named fragment_profile.xml and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical"> <EditText android:id="@+id/editTextName" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter name " android:inputType="text" /> <EditText android:id="@+id/editTextEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter email " android:inputType="textEmailAddress" /> <EditText android:id="@+id/editTextPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter password " android:inputType="textPassword" /> <RadioGroup android:id="@+id/radioGender" android:layout_width="match_parent" android:layout_height="wrap_content"> <RadioButton android:id="@+id/radioMale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Male" /> <RadioButton android:id="@+id/radioFemale" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Female" /> </RadioGroup> <Button android:id="@+id/buttonSignIn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Update" /> </LinearLayout> </RelativeLayout> |
- It will look like this.
- Now the last fragment is Messages fragment.
Designing Messages Fragment
- Again create a new file named fragment_messages.xml and write the following code. Here we are again using RecyclerView to display the messages received by the user in a list.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerViewMessages" android:layout_width="match_parent" android:layout_height="wrap_content"> </android.support.v7.widget.RecyclerView> </LinearLayout> |
- Again we will define a list layout for the recycler view. So create a file named list_messages.xml and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<?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="wrap_content" android:orientation="vertical"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <TextView android:id="@+id/textViewName" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Belal Khan" /> <TextView android:id="@+id/textViewTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Greetings!" android:textAppearance="@style/Base.TextAppearance.AppCompat.Large" /> <TextView android:id="@+id/textViewMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Lorem ipsum dolor sit camet lorem ipsum dolor sit camet lorem ipsum" android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium" /> <TextView android:id="@+id/textViewTime" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="30/04/1993 10:25am" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> |
- So we have designed all the screen needed in the application. Now lets start coding the application.
Coding Screens
- First create 4 packages inside your main package to make everything organized. I have created activities, api, fragments, model.Â
- As you can see I have moved all the activities inside activities package. This is only to keep the things organized. Now come to MainActivity.java.
Defining Base URL
- Inside api package create a class named APIUrl.java and inside this class we will define the base url of our API. Remember you are not allowed to use localhost here, you need to find the ip of your system if you are using localhost (I am using xampp). For windows use ipconfig and for Mac or Linux use ifconfig to find the ip.
1 2 3 4 5 6 7 8 9 10 11 |
package net.simplifiedcoding.retrofitexample.api; /** * Created by Belal on 14/04/17. */ public class APIUrl { public static final String BASE_URL = "http://192.168.1.102/RetrofitExample/public/"; } |
Adding Internet Permission
- Go to AndroidManifest.xml and add internet permission.
1 2 3 |
<uses-permission android:name="android.permission.INTERNET" /> |
Coding MainActivity
- MainActivity is very simple we only need to navigate to the respective screen on button press.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package net.simplifiedcoding.retrofitexample.activities; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button buttonSignIn, buttonSignUp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonSignIn = (Button) findViewById(R.id.buttonSignIn); buttonSignUp = (Button) findViewById(R.id.buttonSignUp); buttonSignIn.setOnClickListener(this); buttonSignUp.setOnClickListener(this); } @Override public void onClick(View view) { if (view == buttonSignIn) { startActivity(new Intent(this, SignInActivity.class)); } else if (view == buttonSignUp) { startActivity(new Intent(this, SignUpActivity.class)); } } } |
- Now lets move to coding SignUpActivity.java.
Coding SignUpActivity
Creating Retrofit API
- Now first create a java interface inside api package and name it APIService.java. Here we will define all the API calls.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package net.simplifiedcoding.retrofitexample.api; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import retrofit2.Call; import retrofit2.Callback; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.POST; /** * Created by Belal on 14/04/17. */ public interface APIService { //The register call @FormUrlEncoded @POST("register") Call<Result> createUser( @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender); } |
- So our API is ready. After @Field(“parameter”) we have the parameter value of our API that we created. So it should match with the parameter that is to be passed.
Creating Model
- Retrofit will automatically convert the response to our java object. For this we need to define the Model class. We will define the models inside the package named model that we created.
- Now first analyse the response that we are getting on register.
On Success
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "error": false, "message": "Registered successfully", "user": { "id": 8, "name": "Faiz Khan", "email": "faiz@gmail.com", "gender": "Male" } } |
On Failure
1 2 3 4 5 6 |
{ "error": true, "message": "This email already exist, please login" } |
- As you can see we have error, message and user in the response JSON. So we will create two class for this one will be the Result and other will be User.
- So create two classes inside your model package named Result.java and User.java and write the following codes.
- Result.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package net.simplifiedcoding.retrofitexample.models; import com.google.gson.annotations.SerializedName; /** * Created by Belal on 14/04/17. */ public class Result { @SerializedName("error") private Boolean error; @SerializedName("message") private String message; @SerializedName("user") private User user; public Result(Boolean error, String message, User user) { this.error = error; this.message = message; this.user = user; } public Boolean getError() { return error; } public String getMessage() { return message; } public User getUser() { return user; } } |
- User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package net.simplifiedcoding.retrofitexample.models; /** * Created by Belal on 14/04/17. */ public class User { private int id; private String name; private String email; private String password; private String gender; public User(String name, String email, String password, String gender) { this.name = name; this.email = email; this.password = password; this.gender = gender; } public User(int id, String name, String email, String gender){ this.id = id; this.name = name; this.email = email; this.gender = gender; } public User(int id, String name, String email, String password, String gender) { this.id = id; this.name = name; this.email = email; this.password = password; this.gender = gender; } public int getId() { return id; } public String getName() { return name; } public String getEmail() { return email; } public String getPassword(){ return password; } public String getGender() { return gender; } } |
Getting User Values
- Now come back go SignUpActivity.java and define the view objects and listeners.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
package net.simplifiedcoding.retrofitexample.activities; 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.RadioGroup; import net.simplifiedcoding.retrofitexample.R; public class SignUpActivity extends AppCompatActivity implements View.OnClickListener { private Button buttonSignUp; private EditText editTextName, editTextEmail, editTextPassword; private RadioGroup radioGender; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_up); buttonSignUp = (Button) findViewById(R.id.buttonSignUp); editTextName = (EditText) findViewById(R.id.editTextName); editTextEmail = (EditText) findViewById(R.id.editTextEmail); editTextPassword = (EditText) findViewById(R.id.editTextPassword); radioGender = (RadioGroup) findViewById(R.id.radioGender); buttonSignUp.setOnClickListener(this); } private void userSignUp(){ } @Override public void onClick(View view) { if (view == buttonSignUp) { userSignUp(); } } } |
- Now we will perform the SignUp using Retrofit.
Performing POST Request using Retrofit
- Inside the method userSignUp() write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
private void userSignUp() { //defining a progress dialog to show while signing up final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setMessage("Signing Up..."); progressDialog.show(); //getting the user values final RadioButton radioSex = (RadioButton) findViewById(radioGender.getCheckedRadioButtonId()); String name = editTextName.getText().toString().trim(); String email = editTextEmail.getText().toString().trim(); String password = editTextPassword.getText().toString().trim(); String gender = radioSex.getText().toString(); //building retrofit object Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); //Defining retrofit api service APIService service = retrofit.create(APIService.class); //Defining the user object as we need to pass it with the call User user = new User(name, email, password, gender); //defining the call Call<Result> call = service.createUser( user.getName(), user.getEmail(), user.getPassword(), user.getGender() ); //calling the api call.enqueue(new Callback<Result>() { @Override public void onResponse(Call<Result> call, Response<Result> response) { //hiding progress dialog progressDialog.dismiss(); //displaying the message from the response as toast Toast.makeText(getApplicationContext(), response.body().getMessage(), Toast.LENGTH_LONG).show(); } @Override public void onFailure(Call<Result> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show(); } }); } |
Testing Sign Up Screen
- Run your application now and go to Sign Up Screen and try Signing Up as a new user.
- As you can see we got the success message. Check the MySQL database for the new user.
- See the last row. Bingo! it is working absolutely fine.
Making User Login after Successful Registration
- On the successful registration we will make the user automatically logged in. For this we will use the SharedPreferences to store user data.
- So we will create a new class for managing SharedPreferences.
- Create a new package named helper and inside the package create a class named SharedPrefManager.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
package net.simplifiedcoding.retrofitexample.helper; import android.content.Context; import android.content.SharedPreferences; import net.simplifiedcoding.retrofitexample.models.User; /** * Created by Belal on 14/04/17. */ public class SharedPrefManager { private static SharedPrefManager mInstance; private static Context mCtx; private static final String SHARED_PREF_NAME = "simplifiedcodingsharedprefretrofit"; private static final String KEY_USER_ID = "keyuserid"; private static final String KEY_USER_NAME = "keyusername"; private static final String KEY_USER_EMAIL = "keyuseremail"; private static final String KEY_USER_GENDER = "keyusergender"; private SharedPrefManager(Context context) { mCtx = context; } public static synchronized SharedPrefManager getInstance(Context context) { if (mInstance == null) { mInstance = new SharedPrefManager(context); } return mInstance; } public boolean userLogin(User user) { SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt(KEY_USER_ID, user.getId()); editor.putString(KEY_USER_NAME, user.getName()); editor.putString(KEY_USER_EMAIL, user.getEmail()); editor.putString(KEY_USER_GENDER, user.getGender()); editor.apply(); return true; } public boolean isLoggedIn() { SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); if (sharedPreferences.getString(KEY_USER_EMAIL, null) != null) return true; return false; } public User getUser() { SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); return new User( sharedPreferences.getInt(KEY_USER_ID, 0), sharedPreferences.getString(KEY_USER_NAME, null), sharedPreferences.getString(KEY_USER_EMAIL, null), sharedPreferences.getString(KEY_USER_GENDER, null) ); } public boolean logout() { SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.clear(); editor.apply(); return true; } } |
- Now we need to modify the userSignUp() method of SignUpActivity.java as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
private void userSignUp() { //defining a progress dialog to show while signing up final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setMessage("Signing Up..."); progressDialog.show(); //getting the user values final RadioButton radioSex = (RadioButton) findViewById(radioGender.getCheckedRadioButtonId()); String name = editTextName.getText().toString().trim(); String email = editTextEmail.getText().toString().trim(); String password = editTextPassword.getText().toString().trim(); String gender = radioSex.getText().toString(); //building retrofit object Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); //Defining retrofit api service APIService service = retrofit.create(APIService.class); //Defining the user object as we need to pass it with the call User user = new User(name, email, password, gender); //defining the call Call<Result> call = service.createUser( user.getName(), user.getEmail(), user.getPassword(), user.getGender() ); //calling the api call.enqueue(new Callback<Result>() { @Override public void onResponse(Call<Result> call, Response<Result> response) { //hiding progress dialog progressDialog.dismiss(); //displaying the message from the response as toast Toast.makeText(getApplicationContext(), response.body().getMessage(), Toast.LENGTH_LONG).show(); //if there is no error if (!response.body().getError()) { //starting profile activity finish(); SharedPrefManager.getInstance(getApplicationContext()).userLogin(response.body().getUser()); startActivity(new Intent(getApplicationContext(), HomeActivity.class)); } } @Override public void onFailure(Call<Result> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show(); } }); } |
- Now again test by registering as a new User and you should automatically log in on success.
- Now come to MainActivity.java and here we will also check if the user is already logged in then we will directly open the profile activity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
package net.simplifiedcoding.retrofitexample.activities; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.helper.SharedPrefManager; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button buttonSignIn, buttonSignUp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //if user is already logged in openeing the profile activity if (SharedPrefManager.getInstance(this).isLoggedIn()) { finish(); startActivity(new Intent(this, HomeActivity.class)); } buttonSignIn = (Button) findViewById(R.id.buttonSignIn); buttonSignUp = (Button) findViewById(R.id.buttonSignUp); buttonSignIn.setOnClickListener(this); buttonSignUp.setOnClickListener(this); } @Override public void onClick(View view) { if (view == buttonSignIn) { startActivity(new Intent(this, SignInActivity.class)); } else if (view == buttonSignUp) { startActivity(new Intent(this, SignUpActivity.class)); } } } |
- Now run your application again and you will be directly navigated to the Home Activity. Now we will code the User Sign In Activity.
Coding Sign In Activity
Creating Retrofit API
- Again we will create a new API call inside APIService interface for the Sign In.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package net.simplifiedcoding.retrofitexample.api; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import retrofit2.Call; import retrofit2.Callback; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.POST; /** * Created by Belal on 14/04/17. */ public interface APIService { @FormUrlEncoded @POST("register") Call<Result> createUser( @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender); //the signin call @FormUrlEncoded @POST("login") Call<Result> userLogin( @Field("email") String email, @Field("password") String password ); } |
Making User Sign In
- Now inside SignInActivity.java write the following code. We are doing almost the same we did in SignUpActivity.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
package net.simplifiedcoding.retrofitexample.activities; import android.app.ProgressDialog; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.RadioButton; import android.widget.Toast; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.api.APIUrl; import net.simplifiedcoding.retrofitexample.helper.SharedPrefManager; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class SignInActivity extends AppCompatActivity implements View.OnClickListener { private EditText editTextEmail, editTextPassword; private Button buttonSignIn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_in); editTextEmail = (EditText) findViewById(R.id.editTextEmail); editTextPassword = (EditText) findViewById(R.id.editTextPassword); buttonSignIn = (Button) findViewById(R.id.buttonSignIn); buttonSignIn.setOnClickListener(this); } private void userSignIn() { final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setMessage("Signing Up..."); progressDialog.show(); String email = editTextEmail.getText().toString().trim(); String password = editTextPassword.getText().toString().trim(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); APIService service = retrofit.create(APIService.class); Call<Result> call = service.userLogin(email, password); call.enqueue(new Callback<Result>() { @Override public void onResponse(Call<Result> call, Response<Result> response) { progressDialog.dismiss(); if (!response.body().getError()) { finish(); SharedPrefManager.getInstance(getApplicationContext()).userLogin(response.body().getUser()); startActivity(new Intent(getApplicationContext(), HomeActivity.class)); } else { Toast.makeText(getApplicationContext(), "Invalid email or password", Toast.LENGTH_LONG).show(); } } @Override public void onFailure(Call<Result> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show(); } }); } @Override public void onClick(View view) { if (view == buttonSignIn) { userSignIn(); } } } |
- Now we will code the home fragment where we will display a list of all users.
Coding Home Activity
- Every other screen is inside this activity using fragments so first we will define a FrameLayout where we will switch the fragments.
- So come inside content_home.xml and modify it as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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/content_home" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="net.simplifiedcoding.retrofitexample.activities.HomeActivity" tools:showIn="@layout/app_bar_home"> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> |
- Now open HomeActivity.java and modify it as below. For more details about this activity you can go through the Android Navigation Drawer Tutorial.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
package net.simplifiedcoding.retrofitexample.activities; import android.content.Intent; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.fragments.HomeFragment; import net.simplifiedcoding.retrofitexample.fragments.MessageFragment; import net.simplifiedcoding.retrofitexample.fragments.ProfileFragment; import net.simplifiedcoding.retrofitexample.helper.SharedPrefManager; public class HomeActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private TextView textViewName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); if (!SharedPrefManager.getInstance(this).isLoggedIn()) { finish(); startActivity(new Intent(this, SignInActivity.class)); } View headerView = navigationView.getHeaderView(0); textViewName = (TextView) headerView.findViewById(R.id.textViewName); textViewName.setText(SharedPrefManager.getInstance(this).getUser().getName()); //loading home fragment by default displaySelectedScreen(R.id.nav_home); } @Override public void onBackPressed() { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } private void displaySelectedScreen(int itemId) { Fragment fragment = null; switch (itemId) { case R.id.nav_home: fragment = new HomeFragment(); break; case R.id.nav_profile: fragment = new ProfileFragment(); break; case R.id.nav_messages: fragment = new MessageFragment(); break; case R.id.nav_logout: logout(); break; } //replacing the fragment if (fragment != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.content_frame, fragment); ft.commit(); } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); } private void logout() { SharedPrefManager.getInstance(this).logout(); finish(); startActivity(new Intent(this, SignInActivity.class)); } @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(MenuItem item) { displaySelectedScreen(item.getItemId()); return true; } } |
Building Home Fragment
- In the Home Fragment we will display list of all the users from the database. For this we already have the API http://localhost/RetrofitExample/public/users. The response of this GET call is.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
{ "users": [ { "id": 1, "name": "Bhaque khan", "email": "bh@gmail.com", "gender": "Male" }, { "id": 2, "name": "Ramiz Khan", "email": "bela12@gmail.com", "gender": "Male" }, { "id": 3, "name": "Belal Khan", "email": "b1ela12@gmail.com", "gender": "Male" }, { "id": 4, "name": "Belal Khan", "email": "xyz@gmail.com", "gender": "Male" }, |
- To store it we will define one more model inside models package. So create a class named Users and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package net.simplifiedcoding.retrofitexample.models; import java.util.ArrayList; /** * Created by Belal on 14/04/17. */ public class Users { private ArrayList<User> users; public Users() { } public ArrayList<User> getUsers() { return users; } public void setUsers(ArrayList<User> users) { this.users = users; } } |
- Now we will build our Custom RecyclerView Adapter to display User List. So create a class named UserAdapter.java inside helper package and write the following code. If you need more detail about RecyclerView you can go through this RecyclerView Tutorial.Â
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
package net.simplifiedcoding.retrofitexample.helper; 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.ImageButton; import android.widget.TextView; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.models.User; import java.util.List; import static android.R.id.list; /** * Created by Belal on 14/04/17. */ public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> { private List<User> users; private Context mCtx; public UserAdapter(List<User> users, Context mCtx) { this.users = users; this.mCtx = mCtx; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_users, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(UserAdapter.ViewHolder holder, int position) { User user = users.get(position); holder.textViewName.setText(user.getName()); } @Override public int getItemCount() { return users.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView textViewName; public ImageButton imageButtonMessage; public ViewHolder(View itemView) { super(itemView); textViewName = (TextView) itemView.findViewById(R.id.textViewName); imageButtonMessage = (ImageButton) itemView.findViewById(R.id.imageButtonMessage); } } } |
- Now inside the fragments package create a new class named HomeFragment.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
package net.simplifiedcoding.retrofitexample.fragments; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.api.APIUrl; import net.simplifiedcoding.retrofitexample.helper.UserAdapter; import net.simplifiedcoding.retrofitexample.models.Users; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; /** * Created by Belal on 14/04/17. */ public class HomeFragment extends Fragment { private RecyclerView recyclerViewUsers; private RecyclerView.Adapter adapter; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_home, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getActivity().setTitle("Home"); recyclerViewUsers = (RecyclerView) view.findViewById(R.id.recyclerViewUsers); recyclerViewUsers.setHasFixedSize(true); recyclerViewUsers.setLayoutManager(new LinearLayoutManager(getActivity())); Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); APIService service = retrofit.create(APIService.class); Call<Users> call = service.getUsers(); call.enqueue(new Callback<Users>() { @Override public void onResponse(Call<Users> call, Response<Users> response) { adapter = new UserAdapter(response.body().getUsers(), getActivity()); recyclerViewUsers.setAdapter(adapter); } @Override public void onFailure(Call<Users> call, Throwable t) { } }); } } |
- Now come inside HomeActivity.java and modify the method displaySelectedScreen() as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
private void displaySelectedScreen(int itemId) { Fragment fragment = null; switch (itemId) { case R.id.nav_home: fragment = new HomeFragment(); break; case R.id.nav_profile: break; case R.id.nav_messages: break; case R.id.nav_logout: break; } //replacing the fragment if (fragment != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.content_frame, fragment); ft.commit(); } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); } |
- Now try running the application.
- So its working fine. Now we will code the functionality for the message icon, it should open an alert dialog to send message to the selected user. We already have the layout for the custom alert dialog.
Making Custom Alert Input for Sending Message
- Again come inside the UserAdapter.java class and modify it as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
package net.simplifiedcoding.retrofitexample.helper; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.ImageButton; import android.widget.TextView; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.models.User; import java.util.List; import static android.R.id.list; /** * Created by Belal on 14/04/17. */ public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> { private List<User> users; private Context mCtx; public UserAdapter(List<User> users, Context mCtx) { this.users = users; this.mCtx = mCtx; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_users, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(UserAdapter.ViewHolder holder, int position) { final User user = users.get(position); holder.textViewName.setText(user.getName()); holder.imageButtonMessage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { LayoutInflater li = LayoutInflater.from(mCtx); View promptsView = li.inflate(R.layout.dialog_send_message, null); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mCtx); alertDialogBuilder.setView(promptsView); final EditText editTextTitle = (EditText) promptsView.findViewById(R.id.editTextTitle); final EditText editTextMessage = (EditText) promptsView.findViewById(R.id.editTextMessage); alertDialogBuilder .setCancelable(false) .setPositiveButton("Send", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { //getting the values String title = editTextTitle.getText().toString().trim(); String message = editTextMessage.getText().toString().trim(); //sending the message sendMessage(user.getId(), title, message); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } }); } //method to send message to the user private void sendMessage(int id, String title, String message){ } @Override public int getItemCount() { return users.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView textViewName; public ImageButton imageButtonMessage; public ViewHolder(View itemView) { super(itemView); textViewName = (TextView) itemView.findViewById(R.id.textViewName); imageButtonMessage = (ImageButton) itemView.findViewById(R.id.imageButtonMessage); } } } |
- Now try running the application and on the message icon click you will see an alert dialog asking for message inputs.
- Now we will code for sending the message. We already have API for this.
Sending Message to The User
- We are not using any FCM so the user will not be notified for the message, the recipient can only see the received message when he opens the app.
- First we will define a model for the send message api response. The response is.
1 2 3 4 5 6 |
{ "error": false, "message": "Message sent successfully" } |
- So inside models create a new java class named MessageResponse.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package net.simplifiedcoding.retrofitexample.models; /** * Created by Belal on 15/04/17. */ public class MessageResponse { private boolean error; private String message; public MessageResponse() { } public boolean isError() { return error; } public void setError(boolean error) { this.error = error; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } |
- So first we will define a new API Call in APIService.java file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package net.simplifiedcoding.retrofitexample.api; import net.simplifiedcoding.retrofitexample.models.MessageResponse; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import net.simplifiedcoding.retrofitexample.models.Users; import retrofit2.Call; import retrofit2.Callback; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; /** * Created by Belal on 14/04/17. */ public interface APIService { @FormUrlEncoded @POST("register") Call<Result> createUser( @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender); @FormUrlEncoded @POST("login") Call<Result> userLogin( @Field("email") String email, @Field("password") String password ); @GET("users") Call<Users> getUsers(); //sending message @FormUrlEncoded @POST("sendmessage") Call<MessageResponse> sendMessage( @Field("from") int from, @Field("to") int to, @Field("title") String title, @Field("message") String message); } |
- Now inside UserAdapter.java define the sendMessage() method as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
private void sendMessage(int id, String title, String message) { final ProgressDialog progressDialog = new ProgressDialog(mCtx); progressDialog.setMessage("Sending Message..."); progressDialog.show(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); APIService service = retrofit.create(APIService.class); Call<MessageResponse> call = service.sendMessage( SharedPrefManager.getInstance(mCtx).getUser().getId(), id, title, message ); call.enqueue(new Callback<MessageResponse>() { @Override public void onResponse(Call<MessageResponse> call, Response<MessageResponse> response) { progressDialog.dismiss(); Toast.makeText(mCtx, response.body().getMessage(), Toast.LENGTH_LONG).show(); } @Override public void onFailure(Call<MessageResponse> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(mCtx, t.getMessage(), Toast.LENGTH_LONG).show(); } }); } |
- Now test your application.
- Yes it is working fine. So the HomeFragment is finished. Now we will build the next profile fragment.
Building Profile Fragment
- Inside Profile Fragment user can update the details. So for updating we have the API. So to make the api call we will again define a new API Call inside APIService.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package net.simplifiedcoding.retrofitexample.api; import net.simplifiedcoding.retrofitexample.models.MessageResponse; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import net.simplifiedcoding.retrofitexample.models.Users; import retrofit2.Call; import retrofit2.Callback; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Path; /** * Created by Belal on 14/04/17. */ public interface APIService { @FormUrlEncoded @POST("register") Call<Result> createUser( @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender); @FormUrlEncoded @POST("login") Call<Result> userLogin( @Field("email") String email, @Field("password") String password ); @GET("users") Call<Users> getUsers(); @FormUrlEncoded @POST("sendmessage") Call<MessageResponse> sendMessage( @Field("from") int from, @Field("to") int to, @Field("title") String title, @Field("message") String message); //updating user @FormUrlEncoded @POST("update/{id}") Call<Result> updateUser( @Path("id") int id, @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender ); } |
- Now create a new class named ProfileFragment.java inside fragments package and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
package net.simplifiedcoding.retrofitexample.fragments; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Toast; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.activities.HomeActivity; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.api.APIUrl; import net.simplifiedcoding.retrofitexample.helper.SharedPrefManager; import net.simplifiedcoding.retrofitexample.helper.UserAdapter; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import net.simplifiedcoding.retrofitexample.models.Users; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; /** * Created by Belal on 14/04/17. */ public class ProfileFragment extends Fragment implements View.OnClickListener { private Button buttonUpdate; private EditText editTextName, editTextEmail, editTextPassword; private RadioGroup radioGender; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_profile, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getActivity().setTitle("Profile"); buttonUpdate = (Button) view.findViewById(R.id.buttonUpdate); editTextName = (EditText) view.findViewById(R.id.editTextName); editTextEmail = (EditText) view.findViewById(R.id.editTextEmail); editTextPassword = (EditText) view.findViewById(R.id.editTextPassword); radioGender = (RadioGroup) view.findViewById(R.id.radioGender); buttonUpdate.setOnClickListener(this); User user = SharedPrefManager.getInstance(getActivity()).getUser(); editTextName.setText(user.getName()); editTextEmail.setText(user.getEmail()); editTextPassword.setText("0000"); if (user.getGender().equalsIgnoreCase("male")) { radioGender.check(R.id.radioMale); } else { radioGender.check(R.id.radioFemale); } } private void updateUser() { final ProgressDialog progressDialog = new ProgressDialog(getActivity()); progressDialog.setMessage("Updating..."); progressDialog.show(); final RadioButton radioSex = (RadioButton) getActivity().findViewById(radioGender.getCheckedRadioButtonId()); String name = editTextName.getText().toString().trim(); String email = editTextEmail.getText().toString().trim(); String password = editTextPassword.getText().toString().trim(); String gender = radioSex.getText().toString(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); APIService service = retrofit.create(APIService.class); User user = new User(SharedPrefManager.getInstance(getActivity()).getUser().getId(), name, email, password, gender); Call<Result> call = service.updateUser( user.getId(), user.getName(), user.getEmail(), user.getPassword(), user.getGender() ); call.enqueue(new Callback<Result>() { @Override public void onResponse(Call<Result> call, Response<Result> response) { progressDialog.dismiss(); Toast.makeText(getActivity(), response.body().getMessage(), Toast.LENGTH_LONG).show(); if (!response.body().getError()) { SharedPrefManager.getInstance(getActivity()).userLogin(response.body().getUser()); } } @Override public void onFailure(Call<Result> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_LONG).show(); } }); } @Override public void onClick(View view) { if (view == buttonUpdate) { updateUser(); } } } |
- Now again inside HomeActivity.java we need to modify the method displaySelectedScreen() as below to show the Profile Fragment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
private void displaySelectedScreen(int itemId) { Fragment fragment = null; switch (itemId) { case R.id.nav_home: fragment = new HomeFragment(); break; case R.id.nav_profile: fragment = new ProfileFragment(); break; case R.id.nav_messages: break; case R.id.nav_logout: break; } //replacing the fragment if (fragment != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.content_frame, fragment); ft.commit(); } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); } |
- Now test the application and try updating the values.
- So it is working fine.
Building Messages Fragment
- The API returning the messages in the following format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{ "messages": [ { "id": 1, "from": "Bhaque khan", "to": "Ramiz Khan", "title": "Greetings!", "message": "Hello how are you?", "sent": "2017-04-13 22:43:38" }, { "id": 2, "from": "Bhaque khan", "to": "Ramiz Khan", "title": "greetings!", "message": "hello wassup?", "sent": "2017-04-13 22:48:07" }, { "id": 3, "from": "Bhaque khan", "to": "Ramiz Khan", "title": "Heya Heya", "message": "Yo", "sent": "2017-04-15 00:05:33" } ] } |
- So to model the above data we need to classes. So first create a class named Message.java inside models package.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package net.simplifiedcoding.retrofitexample.models; /** * Created by Belal on 15/04/17. */ public class Message { private int id; private int from; private int to; private String title; private String message; private String sent; public Message(int id, int from, int to, String title, String message, String sent) { this.id = id; this.from = from; this.to = to; this.title = title; this.message = message; this.sent = sent; } public int getId() { return id; } public int getFrom() { return from; } public int getTo() { return to; } public String getTitle() { return title; } public String getMessage() { return message; } public String getSent() { return sent; } } |
- Now create a class named Messages.java in models package.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package net.simplifiedcoding.retrofitexample.models; import java.util.ArrayList; /** * Created by Belal on 15/04/17. */ public class Messages { private ArrayList<Message> messages; public Messages() { } public ArrayList<Message> getMessages() { return messages; } public void setMessages(ArrayList<Message> messages) { this.messages = messages; } } |
- Now we will make a new API call inside APIService.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
package net.simplifiedcoding.retrofitexample.api; import net.simplifiedcoding.retrofitexample.models.MessageResponse; import net.simplifiedcoding.retrofitexample.models.Messages; import net.simplifiedcoding.retrofitexample.models.Result; import net.simplifiedcoding.retrofitexample.models.User; import net.simplifiedcoding.retrofitexample.models.Users; import retrofit2.Call; import retrofit2.Callback; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Path; /** * Created by Belal on 14/04/17. */ public interface APIService { @FormUrlEncoded @POST("register") Call<Result> createUser( @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender); @FormUrlEncoded @POST("login") Call<Result> userLogin( @Field("email") String email, @Field("password") String password ); @GET("users") Call<Users> getUsers(); @FormUrlEncoded @POST("sendmessage") Call<MessageResponse> sendMessage( @Field("from") int from, @Field("to") int to, @Field("title") String title, @Field("message") String message); @FormUrlEncoded @POST("update/{id}") Call<Result> updateUser( @Path("id") int id, @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("gender") String gender ); //getting messages @GET("messages/{id}") Call<Messages> getMessages(@Path("id") int id); } |
- To display all the message again we need an adapter so create a class inside helper package named MessageAdapter.java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
package net.simplifiedcoding.retrofitexample.helper; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.api.APIUrl; import net.simplifiedcoding.retrofitexample.models.Message; import net.simplifiedcoding.retrofitexample.models.MessageResponse; import net.simplifiedcoding.retrofitexample.models.User; import java.util.List; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; /** * Created by Belal on 14/04/17. */ public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.ViewHolder> { private List<Message> messages; private Context mCtx; public MessageAdapter(List<Message> messages, Context mCtx) { this.messages = messages; this.mCtx = mCtx; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_messages, parent, false); return new ViewHolder(v); } @Override public void onBindViewHolder(MessageAdapter.ViewHolder holder, int position) { final Message message = messages.get(position); holder.textViewName.setText(message.getFrom()); holder.textViewTitle.setText(message.getTitle()); holder.textViewMessage.setText(message.getMessage()); holder.textViewTime.setText(message.getSent()); } @Override public int getItemCount() { return messages.size(); } public class ViewHolder extends RecyclerView.ViewHolder { public TextView textViewName; public TextView textViewTitle; public TextView textViewMessage; public TextView textViewTime; public ViewHolder(View itemView) { super(itemView); textViewName = (TextView) itemView.findViewById(R.id.textViewName); textViewTitle = (TextView) itemView.findViewById(R.id.textViewTitle); textViewMessage = (TextView) itemView.findViewById(R.id.textViewMessage); textViewTime = (TextView) itemView.findViewById(R.id.textViewTime); } } } |
- Now create a new class inside fragments package named MessageFragment.java and write the following code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
package net.simplifiedcoding.retrofitexample.fragments; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import net.simplifiedcoding.retrofitexample.R; import net.simplifiedcoding.retrofitexample.api.APIService; import net.simplifiedcoding.retrofitexample.api.APIUrl; import net.simplifiedcoding.retrofitexample.helper.MessageAdapter; import net.simplifiedcoding.retrofitexample.helper.SharedPrefManager; import net.simplifiedcoding.retrofitexample.helper.UserAdapter; import net.simplifiedcoding.retrofitexample.models.Messages; import net.simplifiedcoding.retrofitexample.models.Users; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; /** * Created by Belal on 14/04/17. */ public class MessageFragment extends Fragment { private RecyclerView recyclerViewMessages; private RecyclerView.Adapter adapter; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_messages, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getActivity().setTitle("Messages"); recyclerViewMessages = (RecyclerView) view.findViewById(R.id.recyclerViewMessages); recyclerViewMessages.setHasFixedSize(true); recyclerViewMessages.setLayoutManager(new LinearLayoutManager(getActivity())); Retrofit retrofit = new Retrofit.Builder() .baseUrl(APIUrl.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); APIService service = retrofit.create(APIService.class); Call<Messages> call = service.getMessages(SharedPrefManager.getInstance(getActivity()).getUser().getId()); call.enqueue(new Callback<Messages>() { @Override public void onResponse(Call<Messages> call, Response<Messages> response) { adapter = new MessageAdapter(response.body().getMessages(), getActivity()); recyclerViewMessages.setAdapter(adapter); } @Override public void onFailure(Call<Messages> call, Throwable t) { Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_LONG).show(); } }); } } |
- Now again we need to modify the displaySelectedScreen() method on HomeActivity.java file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
private void displaySelectedScreen(int itemId) { Fragment fragment = null; switch (itemId) { case R.id.nav_home: fragment = new HomeFragment(); break; case R.id.nav_profile: fragment = new ProfileFragment(); break; case R.id.nav_messages: fragment = new MessageFragment(); break; case R.id.nav_logout: logout(); break; } //replacing the fragment if (fragment != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.content_frame, fragment); ft.commit(); } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); } private void logout() { SharedPrefManager.getInstance(this).logout(); finish(); startActivity(new Intent(this, SignInActivity.class)); } |
- We also defined the logout this time to make logout work as well. So now everything has finished in the application.
- Bingo! it is working absolutely fine.
- If you are having confusions or troubles you can get my source code from the below given link.
Retrofit Android Tutorial Source Code Download
Android Studio Project
Retrofit Android Tutorial Source Code
So that’s all for this Retrofit Android Tutorial friends. It was the longest post I have written so far, so please follow it carefully. If you are having any confusions or queries regarding this Retrofit Android Tutorial, then let’s start a discussion on the comments section. Also if you found some errors about this Retrofit Android Tutorial then do let me know in the comments. And if you liked this post and found it useful you can SHARE it on your social networks. Thank You 🙂