Android (Kotlin) Login and Register example with Retrofit
Output :
Create Table :
PHP Files :
config.php
<?php
$host="localhost";
$user="root";
$password="";
$db = "kotlin_example";
$con = mysqli_connect($host,$user,$password,$db);
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}else{ //echo "Connect";
}
?>
register.php
<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
include_once("config.php");
$postdata = file_get_contents("php://input");
if (isset($postdata)) {
$request1 = json_decode($postdata);
$email = $request1->email;
$username = $request1->username;
$password = $request1->password;
if($email == '' || $username == '' || $password == ''){
echo json_encode(array( "status" => "false","message" => "Parameter missing!") );
}else{
$query= "SELECT * FROM user WHERE username='$username'";
$result= mysqli_query($con, $query);
if(mysqli_num_rows($result) > 0){
echo json_encode(array( "status" => "false","message" => "Username already exist!") );
}else{
$query = "INSERT INTO user (email,username,password) VALUES ('$email','$username','$password')";
if(mysqli_query($con,$query)){
$query= "SELECT * FROM user WHERE username='$username'";
$result= mysqli_query($con, $query);
$emparray = array();
if(mysqli_num_rows($result) > 0){
while ($row = mysqli_fetch_assoc($result)) {
$emparray[] = $row;
echo json_encode(array( "status" => "true","message" => "Successfully registered!" , "data" => $row) );
}
}
}else{
echo json_encode(array( "status" => "false","message" => "Error occured, please try again!") );
}
}
mysqli_close($con);
}
}
} else{
echo json_encode(array( "status" => "false","message" => "Error occured, please try again!") );
}
?>
login.php
<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
include_once("config.php");
$postdata = file_get_contents("php://input");
if (isset($postdata)) {
$request1 = json_decode($postdata);
$email = $request1->email;
$password = $request1->password;
if( $email == '' || $password == '' ){
echo json_encode(array( "status" => false,"message" => "Parameter missing!") );
}else{
$query= "SELECT * FROM user WHERE email='$email' AND password='$password'";
$result= mysqli_query($con, $query);
if(mysqli_num_rows($result) > 0){
$query= "SELECT * FROM user WHERE email='$email' AND password='$password'";
$result= mysqli_query($con, $query);
$emparray;
if(mysqli_num_rows($result) > 0){
while ($row = mysqli_fetch_assoc($result)) {
$emparray = $row;
}
}
echo json_encode(array( "status" => true,"message" => "Login successfully!", "data" => $emparray) );
}else{
echo json_encode(array( "status" => false,"message" => "Invalid email or password!") );
}
mysqli_close($con);
}
}
} else{
echo json_encode(array( "status" => false,"message" => "Error occured, please try again!") );
}
?>
get_user_detail.php
<?php
$response = array();
include_once("config.php");
if (isset($_GET["id"])) {
$id = $_GET['id'];
$query= "SELECT * FROM user WHERE id='$id'";
$result= mysqli_query($con, $query);
$emparray;
if(mysqli_num_rows($result) > 0){
while ($row = mysqli_fetch_assoc($result)) {
$emparray = $row;
echo json_encode(array( "status" => true, "data" => $emparray) );
}
}
else{
echo json_encode(array( "status" => false,"message" => "No User Found!") );
}
}else {
echo json_encode(array( "status" => false,"message" => "Required field(s) is missing!") )
}
?>
build.gradle
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0' implementation 'com.google.android.material:material:1.0.0'
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.hpos.loginregisterusingretrofit">
<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"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning"
tools:targetApi="m">
<activity android:name=".HomeActivity"></activity>
<activity android:name=".RegisterActivity" />
<activity android:name=".LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Models
SigninRequest.kt
package com.hpos.loginregisterusingretrofit.models
import com.google.gson.annotations.SerializedName
class SigninRequest(@SerializedName("email") var email: String,
@SerializedName("password") var password: String)
SigninResponse.kt
package com.hpos.loginregisterusingretrofit.models
class SigninResponse(val status: Boolean, val message:String, val data: User)
SignupRequest.kt
package com.hpos.loginregisterusingretrofit.models
import com.google.gson.annotations.SerializedName
class SignupRequest(@SerializedName("email") var email: String,
@SerializedName("username") var username: String,
@SerializedName("password") var password: String)
SignupResponse.kt
package com.hpos.loginregisterusingretrofit.models
class SignupResponse(val status: Boolean, val message:String, val data: User)
UserResponse.kt
package com.hpos.loginregisterusingretrofit.models
data class UserResponse(val status: Boolean, val data: User)
User.kt
package com.hpos.loginregisterusingretrofit.models;
data class User(val id:Int, val username:String, val email:String, val password:String)
Retrofit Files
ApiList
package com.hpos.loginregisterusingretrofit.api
import com.hpos.loginregisterusingretrofit.models.*
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
interface ApiList {
//TODO : Register User
@POST("register.php")
fun doRegister(
@Body signupRequest: SignupRequest
): Call<SignupResponse> // body data
//TODO : Login User
@POST("login.php")
fun doLogin(
@Body signinRequest: SigninRequest
): Call<SigninResponse> // body data
//TODO : Get User
@GET("get_user_detail.php")
fun getUser(@Query("id") id: String): Call<UserResponse>
}
ApiService
package com.hpos.loginregisterusingretrofit.api
import retrofit2.Retrofit
object ApiService {
private val TAG = "--ApiService"
private const val BASE_URL = "http://192.168.1.111/KotlinExample/LoginRegistration/"
fun loginApiCall() = Retrofit.Builder()
.baseUrl(BASE_URL)
// .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(ApiWorker.gsonConverter)
.client(ApiWorker.client)
.build()
.create(ApiList::class.java)!!
}
ApiWorker
package com.hpos.loginregisterusingretrofit.api
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.converter.gson.GsonConverterFactory
import java.security.KeyManagementException
import java.security.NoSuchAlgorithmException
import java.util.concurrent.TimeUnit
object ApiWorker {
private var mClient: OkHttpClient? = null
private var mGsonConverter: GsonConverterFactory? = null
/**
* Don't forget to remove Interceptors (or change Logging Level to NONE)
* in production! Otherwise people will be able to see your request and response on Log Cat.
*/
val client: OkHttpClient
@Throws(NoSuchAlgorithmException::class, KeyManagementException::class)
get() {
if (mClient == null) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val httpBuilder = OkHttpClient.Builder()
httpBuilder
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.addInterceptor(interceptor) /// show all JSON in logCat
.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
// .addHeader("Authorization", AUTH)
.addHeader("Content-Type", "application/json")
// .method(original.method(), original.body())
val request = requestBuilder.build()
chain.proceed(request)
}
mClient = httpBuilder.build()
}
return mClient!!
}
val gsonConverter: GsonConverterFactory
get() {
if (mGsonConverter == null) {
mGsonConverter = GsonConverterFactory
.create(
GsonBuilder()
.setLenient()
.disableHtmlEscaping()
.create()
)
}
return mGsonConverter!!
}
}
Screens Files
HomeActivity.kt
package com.hpos.loginregisterusingretrofit
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import android.widget.Toast
import com.hpos.loginregisterusingretrofit.api.ApiService
import com.hpos.loginregisterusingretrofit.models.User
import com.hpos.loginregisterusingretrofit.models.UserResponse
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class HomeActivity : AppCompatActivity() {
var userId: String = "";
private lateinit var txt_name: TextView
private lateinit var txt_email: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
setTitle("Home")
val intent = getIntent()
userId = intent.getIntExtra("id", 0).toString()
txt_name = findViewById(R.id.txt_name) as TextView
txt_email = findViewById(R.id.txt_email) as TextView
getUser()
}
private fun getUser() {
ApiService.loginApiCall().getUser(userId).enqueue(object : Callback<UserResponse> {
override fun onResponse(
call: Call<UserResponse>,
response: Response<UserResponse>) {
Log.d("Response User ::::", response.body().toString())
if (response.body()!!.status){
txt_name.setText(response.body()!!.data.username)
txt_email.setText(response.body()!!.data.email)
}
}
override fun onFailure(call: Call<UserResponse>, t: Throwable) {
// Log.d("error::::",t?.message)
}
})
}
}
activity_home.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/my"
android:layout_gravity="center_horizontal"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name : "
android:textSize="20sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/txt_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Jainish Prajapati"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email : "
android:textSize="20sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/txt_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="jainishprajapati17@gmail.com"
android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
LoginActivity.kt
package com.hpos.loginregisterusingretrofit
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.widget.AppCompatTextView
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputEditText
import com.hpos.loginregisterusingretrofit.api.ApiService
import com.hpos.loginregisterusingretrofit.models.SigninRequest
import com.hpos.loginregisterusingretrofit.models.SigninResponse
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class LoginActivity : Activity(), View.OnClickListener {
private lateinit var ed_email : TextInputEditText
private lateinit var ed_password : TextInputEditText
private lateinit var btn_signin : MaterialButton
private lateinit var txt_sign_up : AppCompatTextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
ed_email = findViewById(R.id.ed_email) as TextInputEditText
ed_password = findViewById(R.id.ed_password) as TextInputEditText
btn_signin = findViewById(R.id.btn_signin) as MaterialButton
txt_sign_up = findViewById(R.id.txt_sign_up) as AppCompatTextView
btn_signin.setOnClickListener(this)
txt_sign_up.setOnClickListener(this)
}
override fun onClick(v: View?) {
when(v?.id){
R.id.txt_sign_up -> {
startActivity(Intent(this@LoginActivity, RegisterActivity::class.java))
}
R.id.btn_signin -> {
if (validation()) {
val json = JSONObject()
json.put("email", ed_email.text.toString())
json.put("password", ed_password.text.toString())
ApiService.loginApiCall().doLogin(
SigninRequest(
ed_email.text.toString(),ed_password.text.toString()
)
).enqueue(object : Callback<SigninResponse> {
override fun onResponse(
call: Call<SigninResponse>,
response: Response<SigninResponse>) {
Log.d("Response::::", response.body().toString())
if (response.body()!!.status){
finish()
val intent = Intent(this@LoginActivity, HomeActivity::class.java)
intent.putExtra("id",response.body()!!.data.id)
startActivity(intent)
}else{
Toast.makeText(applicationContext, response.body()!!.message, Toast.LENGTH_LONG).show()
}
}
override fun onFailure(call: Call<SigninResponse>, t: Throwable) {
}
})
}
}
}
}
fun validation(): Boolean {
var value = true
val password = ed_password.text.toString().trim()
val name = ed_email.text.toString().trim()
if (password.isEmpty()) {
ed_password.error = "Password required"
ed_password.requestFocus()
value = false
}
if (name.isEmpty()) {
ed_email.error = "Email required"
ed_email.requestFocus()
value = false
}
return value;
}
}
activity_login.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="20dp"
android:layout_centerInParent="true">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/signin"
android:textColor="@android:color/black"
android:textStyle="bold"
android:textSize="36sp"/>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/welcome_back"
android:textSize="20sp"
android:textColor="@android:color/darker_gray"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="30dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ed_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:inputType="textEmailAddress"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="10dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ed_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_signin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/sign_in"
android:padding="15dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_marginTop="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/don_t_have_an_account"
android:textSize="20sp"
android:textColor="@android:color/darker_gray"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/txt_sign_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sign_up_here"
android:textSize="20sp"
android:textColor="@android:color/black"
android:layout_marginStart="20dp"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
RegisterActivity.kt
package com.hpos.loginregisterusingretrofit
import android.app.Activity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputEditText
import com.hpos.loginregisterusingretrofit.api.ApiService
import com.hpos.loginregisterusingretrofit.models.SignupRequest
import com.hpos.loginregisterusingretrofit.models.SignupResponse
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class RegisterActivity : Activity(), View.OnClickListener {
private lateinit var ed_username: TextInputEditText
private lateinit var ed_email: TextInputEditText
private lateinit var ed_password: TextInputEditText
private lateinit var btn_signup: MaterialButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
ed_username = findViewById(R.id.ed_username) as TextInputEditText
ed_email = findViewById(R.id.ed_email) as TextInputEditText
ed_password = findViewById(R.id.ed_password) as TextInputEditText
btn_signup = findViewById(R.id.btn_signup) as MaterialButton
btn_signup.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.btn_signup -> {
if (validation()) {
val json = JSONObject()
json.put("email", ed_email.text.toString())
json.put("username", ed_username.text.toString())
json.put("password", ed_password.text.toString())
ApiService.loginApiCall().doRegister(
SignupRequest(
ed_email.text.toString(),
ed_username.text.toString(), ed_password.text.toString()
)
).enqueue(object : Callback<SignupResponse> {
override fun onResponse(
call: Call<SignupResponse>,
response: Response<SignupResponse>
) {
Log.d("Response::::", response.body().toString())
val loginResponse : SignupResponse
loginResponse = response.body()!!
if (loginResponse.status){
finish()
}else{
Toast.makeText(applicationContext, response.body()!!.message, Toast.LENGTH_LONG).show()
}
}
override fun onFailure(call: Call<SignupResponse>, t: Throwable) {
}
})
}
}
}
}
fun validation(): Boolean {
var value = true
val email = ed_email.text.toString().trim()
val password = ed_password.text.toString().trim()
val name = ed_username.text.toString().trim()
if (email.isEmpty()) {
ed_email.error = "Email required"
ed_email.requestFocus()
value = false
}
if (password.isEmpty()) {
ed_password.error = "Password required"
ed_password.requestFocus()
value = false
}
if (name.isEmpty()) {
ed_username.error = "Name required"
ed_username.requestFocus()
value = false
}
return value;
}
}
activity_register.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="20dp"
android:layout_centerInParent="true">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/signup"
android:textColor="@android:color/black"
android:textStyle="bold"
android:textSize="36sp"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/user_name"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="30dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ed_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="10dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ed_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="10dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/ed_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_signup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/sign_up"
android:padding="15dp"/>
</LinearLayout>
</RelativeLayout>
style.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
string.xml
<resources>
<string name="app_name">LoginRegisterUsingRetrofit</string>
<string name="user_name">User Name</string>
<string name="password">Password</string>
<string name="sign_in">Sign In</string>
<string name="signin">Signin</string>
<string name="welcome_back">Welcome back</string>
<string name="sign_up">Sign Up</string>
<string name="email">Email</string>
<string name="signup">Signup</string>
<string name="don_t_have_an_account">Don\'t have an account?</string>
<string name="sign_up_here">Sign up here</string>
</resources>
color.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#5edb92</color>
<color name="colorPrimaryDark">#5edb92</color>
<color name="colorAccent">#5edb92</color>
<color name="colorPrimaryBackground">#0886c7</color>
<color name="colorFormBackground">#e4e4e4</color>
</resources>