CRUD database online | PHP | Volley

Kali ini saya akan berbagi ilmu tentang bagaimana melakukan Create, Read, Update, Delete database dengan menggunakan volley networking library. Dengan php sebagai web service, dan json sebagai pertukaran datanya.

Secara garis besar, langkah-langkah yang harus dilakukan adalah:

  1. Membuat database online.
  2. Membuat beberapa file php dan menyimpannya diserver.
  3. Menambahkan beberapa library dan class pendukung.
  4. Mendisain tampilan aplikasi.
  5. Coding time.

Untuk implementasi CRUD database kali ini, saya contohkan untuk memanajemen user account. Jadi terdapat:

  • Create dalam sign up
  • Read dalam login dan find user
  • Update dalam update username dan password user
  • Delete dalam delete user

Berikut adalah demo hasil jadi aplikasi dari tutorial ini:

Membuat Database Online

Saya menggunakan sebuah server gratisan dari 000webhost.com untuk database dan tempat menyimpan file-file phpnya.

  1. Login ke 000webhost.com(Sign Up dulu jika belum punya akun).
  2. Setelah login, klik Create New untuk membuat domain baru.
  3. Setelah itu, kembali ke list domains, dan klik Go to CPanel sesuai dengan domain yang diinginkan.
  4. Masuk ke MySQL untuk membuat sebuah database.
    1
  5. Isi semuanya, diingat-ingat khususnya passwordnya, karena nanti akan kita gunakan. Setelah terisi semua, klik Create database.
    2

    database = a5648463_andev
    user = a5648463_andev
    password = andevindo123456
    
  6. Setelah itu, kembali ke CPanel, lalu masuk ke phpMyAdmin, lokasinya disebelahnya MySql persis.
  7. Lalu klik Enter phpMyAdmin pada database yang tadi dibuat.

    3
  8. Waktunya membuat database user accountnya sekarang. Buat table dengan nama User Account, lalu isi kolom-kolomnya seperti gambar dibawah:
    4Gambar yang dibawah adalah potongan gambar disebelah kiri, saya potong biar jelas.
  9. Setelah itu klik save, dan database siap digunakan.

Membuat file-file php

File php disini sebagai jembatan antara aplikasi android dengan server. Menerima request dari aplikasi, mengambil data dari database, dan mengembalikannya ke aplikasi android.

Beberapa file yang akan kita buat:

  1. config.php, untuk menyimpang settingan server, seperti database, user, password, host.
  2. connect.php, untuk menyambungkan ke server dengan settingan dari config.php.
  3. function.php, berisi kumpulan fungsi yang digunakan di main.php.
  4. main.php, menangkap parameter dari aplikasi dan memilih fungsi yang akan digunakan sesuai dengan parameter yang dikirim dari aplikasi.
config.php
<?php
	define('DB_USER',"a5648463_andev");
	define('DB_PASSWORD',"andevindo123456");
	define('DB_SERVER',"mysql16.000webhost.com");
	define('DB_DATABASE',"a5648463_andev");
?>

Fungsi dari file config.php ini, menyimpan settingan seperti nama user, password, nama server dan nama database. Dibuat terpisah karena untuk mempermudah maintenancenya kedepan, jika ada perubahan nama user, password dll, cukup merubah yang ada difile config.php ini saja.

Jika data diatas belum dicatat atau lupa, bisa dilihat kembali (kecuali password), dari CPanel masuk ke MySQL

5

connect.php
<?php
include 'config.php';

class CONNECT {
 
    
    function __construct() {
      
        $this->connect();
    }
 
    
    function __destruct() {
        
        $this->close();
    }
 
   
    function connect() {
       
        $con = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD) or die(mysql_error());
 
        
        $db = mysql_select_db(DB_DATABASE) or die(mysql_error()) or die(mysql_error());
 	
       
        return $con;
    }
 
    
    function close() {
        
        mysql_close();
    }
 	
}
 
?>

Fungsi dari file connect.php ini, untuk mempersingkat pemanggilan fungsi connect untuk file-file php lainnya. Fungsi connect kedepannya akan dipakai sangat sering sekali, setiap fungsi yang menggunakan fitur database, harus memanggil fungsi ini, jadinya dengan ada file ini, cukup memanggil connect() saja, maka fungsi connect sudah teratasi.

function.php
<?php
include 'connect.php';


$response = array();

function login($username, $password){
	$db = new connect();
	$query = mysql_query("SELECT * FROM UserAccount WHERE username = '$username'");
	if(mysql_num_rows($query)>0){
		$query = mysql_query("SELECT * FROM UserAccount WHERE username = '$username' AND password = '$password'");
		if(mysql_num_rows($query)>0){
			$response["kode"] = 2;
			$response["pesan"] = "Login berhasil";
			echo json_encode($response);
		}else{
			$response["kode"] = 1;
			$response["pesan"] = "Password tidak cocok";
			echo json_encode($response);
		}
	}else{
		$response["kode"] = 1;
		$response["pesan"] = "Username tidak ditemukan";
		echo json_encode($response);
	}
}

function signUp($username, $password){
	$db = new connect();
	$query = mysql_query("SELECT * FROM UserAccount WHERE username = '$username' ");
	if(mysql_num_rows($query)>0){
		$response["kode"] = 1;
		$response["pesan"] = "Username sudah terdaftar";
		echo json_encode($response);
	}else{
		$query = mysql_query("INSERT INTO UserAccount (username,password) VALUES ('$username','$password')");
		if($query){
			$response["kode"] = 2;
			$response["pesan"] = "SignUp berhasil";
			echo json_encode($response);	
		}else{
			$response["kode"] = 1;
			$response["pesan"] = "Database down";
			echo json_encode($response);
		}
	}
}

function update($usernameBefore, $usernameAfter, $passwordAfter){
	$db = new connect();
	$query = mysql_query("SELECT * FROM UserAccount WHERE username = '$usernameAfter' ");
	if(mysql_num_rows($query)>0){
		$response["kode"] = 1;
		$response["pesan"] = "Username sudah terdaftar";
		echo json_encode($response);
	}else{
		if($usernameAfter == "" && $passwordAfter == ""){
			$response["kode"] = 2;
			$response["pesan"] = "Tidak ada yang dirubah";
			echo json_encode($response);
		}else if($usernameAfter == ""){
			$query = mysql_query("UPDATE UserAccount set password = '$passwordAfter' WHERE username='$usernameBefore'");
			if($query>0){
				$response["kode"] = 2;
				$response["pesan"] = "Password berhasil diubah";
				echo json_encode($response);	
			}else{
				$response["kode"] = 1;
				$response["pesan"] = "Database down";
				echo json_encode($response);
			}
		}else if($passwordAfter == ""){
			$query = mysql_query("UPDATE UserAccount set username = '$usernameAfter' WHERE username='$usernameBefore'");
			if($query>0){
				$response["kode"] = 2;
				$response["pesan"] = "Username berhasil diubah";
				echo json_encode($response);	
			}else{
				$response["kode"] = 1;
				$response["pesan"] = "Database down";
				echo json_encode($response);
			}
		}else{
			$query = mysql_query("UPDATE UserAccount set username = '$usernameAfter', password = '$passwordAfter' WHERE username='$usernameBefore'");
			if($query>0){
				$response["kode"] = 2;
				$response["pesan"] = "Username dan password berhasil diubah";
				echo json_encode($response);	
			}else{
				$response["kode"] = 1;
				$response["pesan"] = "Database down";
				echo json_encode($response);
			}
		}	
	}
	
}

function find($username){
	
	$db = new connect();
	$query = mysql_query("SELECT * FROM UserAccount WHERE username = '$username'");
	if(mysql_num_rows($query)>0){
		$response["kode"] = 2;
		$response["pesan"] = "Username tersedia";
		echo json_encode($response);
	}else{
		$response["kode"] = 1;
		$response["pesan"] = "Username tidak ditemukan";
		echo json_encode($response);
	}
}

function delete($username){
	
	$db = new connect();
	$query = mysql_query("DELETE FROM UserAccount WHERE username = '$username'");
	if($query){
		$response["kode"] = 2;
		$response["pesan"] = "Username berhasil dihapus";
		echo json_encode($response);
	}else{
		$response["kode"] = 1;
		$response["pesan"] = "Database down";
		echo json_encode($response);
	}
}

?>

Fungsi dari file function.php ini, berisi fungsi-fungsi yang digunakan dalam file main.php. Terdapat:

  1. function login, dengan 2 parameter, yaitu username dan password. Fungsinya untuk, sistem login. Mengecek username dan password yang ada didatabase, jika username ada, dan passwordnya cocok, maka akan mengambalikan  kode 2, yang artinya sukses untuk projek ini, kode disini tidak standar, jadi mungkin untuk projek lain, kodenya bisa berbeda-beda setiap kondisinya. Selain itu juga, akan mengambilakan pesan, untuk memberitahukan kepada user hasil apa yang didapat.
  2. function signUp, dengan 2 parameter, username dan password. Fungsinya untuk membuat user baru. Sebelum membuat user baru, username yang diinputkan, akan dicek terlebih dahulu didatabase, jika username telah terdaftar, maka akan dikembalikan kode 1, yang artinya gagal untuk membuat user, karena masalah terkait didalam database, untuk konteks ini yaitu username telah terdaftar. Dan jika berhasil, maka akan mengambilakan nilai 2.
  3. function update, dengan 3 parameter, usernameBefore, usernameAfter dan passwordAfter. usernameBefore adalah username yang akan diganti namanya. usernameAfter adalah nama yang baru sebagai pengganti username lama. passwordAfter, sebagai pengganti password lama. Sebelum melakukan penggantian, akan dilakukan pengecekan usernameAfter, apakah sudah terdaftar atau belum, jika belum maka ke proses pengecekan berikutnya.
    • Jika usernameAfter dan passwordAfter kosong, maka tidak akan ada penggantian.
    • Jika usernameAfter kosong, maka akan dilakukan penggantian untuk password.
    • Jika passwordAfter kosong, maka akan dilakukan penggantian untuk username.
    • Jika usernameAfter dan passwordAfter tidak kosong, maka akan dilakukan penggantian username dan password.
  4. function find, dengan 1 parameter, yaitu username. Fungsinya adalah, untuk mengecek username apakah sudah terdaftar didalam database atau belum. Fungsi ini digunakan sebelum melakukan update atau delete.
  5. function delete, dengan 1 parameter, username. Fungsi ini berguna untuk menghapus sebuah username dalam database.
main.php
<?php
include 'function.php';

$response = array();

$db = new connect();

if(isset($_POST['tag'])){
	$tag = $_POST['tag'];
	if($tag=="login"){
		if(isset($_POST['username']) && isset($_POST['password'])){
			$username = $_POST['username'];
			$password = $_POST['password'];
			login($username,$password);
		}else{
			$response["kode"] = 0;
			$response["pesan"] = "Username atau password tidak boleh kosong!";
			echo json_encode($response);
		}
	}else if($tag=="signUp"){
		if(isset($_POST['username']) && isset($_POST['password'])){
			$username = $_POST['username'];
			$password = $_POST['password'];
			signUp($username,$password);
		}else{
			$response["kode"] = 0;
			$response["pesan"] = "Username atau password tidak boleh kosong!";
			echo json_encode($response);
		}
	}else if($tag=="update"){
		if(isset($_POST['usernameBefore'])){
			$usernameBefore = $_POST['usernameBefore'];
			$usernameAfter = $_POST['username'];
			$passwordAfter = $_POST['password'];
			update($usernameBefore, $usernameAfter, $passwordAfter);
		}else{
			$response["kode"] = 0;
			$response["pesan"] = "Username apa yang ingin diubah?";
			echo json_encode($response);
		}
	}else if($tag=="find"){
		if(isset($_POST['username'])){
			$username = $_POST['username'];
			find($username);
		}else{
			$response["kode"] = 0;
			$response["pesan"] = "Username tidak boleh kosong!";
			echo json_encode($response);
		}
	}else if($tag=="delete"){
		if(isset($_POST['username'])){
			$username = $_POST['username'];
			delete($username);
		}else{
			$response["kode"] = 0;
			$response["pesan"] = "Username tidak boleh kosong!";
			echo json_encode($response);
		}
	}
}else{
	$response["kode"] = 0;
	$response["pesan"] = "Membutuhkan tag untuk proses selanjutnya";
	echo json_encode($response);
}

?>

File main.php ini, adalah file yang dipanggil dalam aplikasi android(Endpoint). Didalam file ini, menerima parameter dari aplikasi berupa tag. Tag ini fungsinya untuk memilih fungsi mana yang akan digunakan.

Menambahkan beberapa library dan class pendukung

Dalam aplikasi ini, dibutuhkan 3 library pendukung, sebagai berikut:

com.android.support:appcompat-v7:23.0.1
com.android.support:design:23.0.1
com.mcxiaoke.volley:library:1.0.19

Agar aplikasi ini bisa berjalan normal, usahakan 3 library diatas sama seperti diatas. Sewaktu-waktu library diatas versinya dapat berubah, dan jika perubahannya mengubah nama fungsi, nama variable atau yang lainnya, maka jika menggunakan library terbarunya, projek ini akan ada yang error.

Cara menggunakan 3 library diatas adalah, masuk ke build.gradle didalam file app. Lalu copy kan 3 file diatas, dengan ditambah compile didepannya, seperti gambar berikut:

9

Letakkan class berikut didalam package Utils. Jika belum ada, klik kanan pada nama package>New>Package

CustomRequest.class
package heends.volleycrud.Utils;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
 * Created by -Andevindo- on 10/8/2015.
 */
public class CustomRequest extends Request<JSONObject> {

    private Response.Listener<JSONObject> listener;
    private Map<String, String> params;

    public CustomRequest(String url, Map<String, String> params,
                         Response.Listener<JSONObject> reponseListener, Response.ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.listener = reponseListener;
        this.params = params;
    }

    public CustomRequest(int method, String url, Map<String, String> params,
                         Response.Listener<JSONObject> reponseListener, Response.ErrorListener errorListener) {
        super(method, url, errorListener);
        this.listener = reponseListener;
        this.params = params;
    }

    protected Map<String, String> getParams()
            throws com.android.volley.AuthFailureError {
        return params;
    }

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString),
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

    @Override
    protected void deliverResponse(JSONObject response) {
        // TODO Auto-generated method stub
        listener.onResponse(response);
    }
}

Class ini menggantikan fungsi post dari library volley, karena untuk versi yang digunakan diprojek ini, fungsi post tersebut masih terdapat bug. Letakkan class ini didalam package Utils, biar tidak kelihatan berantakan.

Mendisain tampilan aplikasi

Tampilan yang akan kita buat, mempunyai sebuah activity dengan tab navigation. Dan mempunyai 4 sub tampilan, yang menggunakan fragment. Tab ini berfungsi untuk mengubah sub tampilan tadi, sesuai dengan tab yang sudah dipilih. 4 sub tampilan ini terdiri dari, Login, SignUp, Update dan Delete.

6

Diatas adalah file-file yang berada dalam folder res.

styles.xml (versi-21)
<resources>
    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>
styles.xml
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.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>
    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>
fragment_update.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="heends.volleycrud.Fragment.UpdateFragment">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Username" />
    </android.support.design.widget.TextInputLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/find"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Find" />

        <ProgressBar
            android:id="@+id/progress_find"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_centerInParent="true"/>/>

    </RelativeLayout>

    <LinearLayout
        android:id="@+id/update_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="gone">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/username_update"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Username" />
        </android.support.design.widget.TextInputLayout>

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <EditText
                android:id="@+id/password_update"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Password"
                android:inputType="textPassword" />
        </android.support.design.widget.TextInputLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Button
                android:id="@+id/update"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="Update" />

            <ProgressBar
                android:id="@+id/progress_update"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:layout_centerInParent="true"/>/>

        </RelativeLayout>


    </LinearLayout>

</LinearLayout>
fragment_sign_up.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="heends.volleycrud.Fragment.SignUpFragment">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Username" />
    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Password"
            android:inputType="textPassword" />
    </android.support.design.widget.TextInputLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/sign_up"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="SignUp" />

        <ProgressBar
            android:id="@+id/progress_sign_up"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_centerInParent="true"/>/>

    </RelativeLayout>


</LinearLayout>
fragment_login.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="heends.volleycrud.Fragment.LoginFragment">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Username" />
    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Password"
            android:inputType="textPassword" />
    </android.support.design.widget.TextInputLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Login" />

        <ProgressBar
            android:id="@+id/progress_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_centerInParent="true"/>/>

    </RelativeLayout>


</LinearLayout>
fragment_delete.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="heends.volleycrud.Fragment.DeleteFragment">

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Username" />
    </android.support.design.widget.TextInputLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/find"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Find" />

        <ProgressBar
            android:id="@+id/progress_find"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_centerInParent="true"/>/>

    </RelativeLayout>

    <LinearLayout
        android:id="@+id/delete_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:visibility="gone"
        android:gravity="center_horizontal">

        <Button
            android:id="@+id/delete"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Delete" />

        <ProgressBar
            android:id="@+id/progress_delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"/>

    </LinearLayout>

</LinearLayout>
activity_main.xml
<?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=".MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"

        ></android.support.v4.view.ViewPager>

    <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.TabLayout
            android:id="@+id/tab"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"></android.support.design.widget.TabLayout>

    </android.support.design.widget.AppBarLayout>


</android.support.design.widget.CoordinatorLayout>

Didalam file-file diatas, terdapat beberapa kode yang menggunakan nama package dari projek, jika ingin membuat projek sendiri, maka:

7

Kenapa saya kasih gambar gede diatas, karena sering kali terjadi error jika murni copy paste saja. Dan juga berlaku untuk class javanya. Jika ada error yang isi terdapat heends.volleycrud, rubahlah dengan nama package anda.

Coding Time

Waktunya melangkah ke pembuatan logicnya. Class yang saya buat disini, saya letakkan dalam package-package sesuai dengan fungsinya, agar kelihatan rapi. Seperti ini:

8

Mohon untuk dibuat classnya semua terlebih dahulu, sebelum dicoba dirun, karena ada beberapa class yang bergantung dengan class lainnya.

Package Utils

VolleySingleton.java
package heends.volleycrud.Utils;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

import heends.volleycrud.Application.MyApplication;

/**
 * Created by -Andevindo- on 10/8/2015.
 */
public class VolleySingleton {

    private static VolleySingleton sInstance = null;
    private RequestQueue mRequestQueue;

    private VolleySingleton(){
        mRequestQueue = Volley.newRequestQueue(MyApplication.getContext());
    }



    public static VolleySingleton getInstance() {
        if(sInstance == null){
            sInstance = new VolleySingleton();
        }
        return sInstance;
    }

    public RequestQueue getRequestQueue(){
        return mRequestQueue;
    }


}

Singleton class adalah class yang membatasi initiasi dari suatu class menjadi satu object saja. Volley menggunakan ini, karena dalam membuat newRequestQueue hanya perlu didefinisinikan sekali saja.

VolleyRequest.java
package heends.volleycrud.Utils;

import android.util.Log;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;


import org.json.JSONObject;

import java.util.Map;

import heends.volleycrud.Interface.VolleyInterface;
import heends.volleycrud.Template.Template;


/**
 * Created by -Andevindo- on 10/8/2015.
 */
public class VolleyRequest {
    private RequestQueue mRequestQueue;
    private CustomRequest mCustomRequest;
    private JsonObjectRequest mJsonObjectRequest;
    private VolleyInterface mVolleyInterface;

    public VolleyRequest(VolleyInterface volleyInterface) {
        mRequestQueue = VolleySingleton.getInstance().getRequestQueue();
        mVolleyInterface = volleyInterface;
    }

    public void sendGetRequest(String endPointAPI) {
        mVolleyInterface.onPrepare();
        mJsonObjectRequest = new JsonObjectRequest(Request.Method.GET,
                endPointAPI,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        mVolleyInterface.onSucces(response);
                        Log.i("Success", response + "");
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                mVolleyInterface.onFailed(error);

            }
        });

        mJsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(Template.VolleyRetryPolicy.SOCKET_TIMEOUT,
                Template.VolleyRetryPolicy.RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        mRequestQueue.add(mJsonObjectRequest);
    }

    public void sendPostRequest(String endPointAPI, Map<String, String> params) {
        mVolleyInterface.onPrepare();
        mCustomRequest = new CustomRequest(Request.Method.POST, endPointAPI, params, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                mVolleyInterface.onSucces(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                mVolleyInterface.onFailed(error);
            }
        });
        mCustomRequest.setRetryPolicy(new DefaultRetryPolicy(Template.VolleyRetryPolicy.SOCKET_TIMEOUT,
                Template.VolleyRetryPolicy.RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        mRequestQueue.add(mCustomRequest);
    }

    public void cancelAllRequest() {
        if (mCustomRequest != null)
            mRequestQueue.cancelAll(mCustomRequest);
        if (mJsonObjectRequest != null)
            mRequestQueue.cancelAll(mJsonObjectRequest);
    }
}
JSONParser.java
package heends.volleycrud.Utils;

import android.content.Context;
import android.widget.Toast;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * Created by -Andevindo- on 10/8/2015.
 */
public class JSONParser {

    private Context mContext;

    public JSONParser(Context context) {
        this.mContext = context;
    }

    public boolean isSuccess(JSONObject jsonObject){
        int kode = 0;
        String pesan = "";
        try {
            kode = jsonObject.getInt("kode");
            pesan = jsonObject.getString("pesan");
        } catch (JSONException e) {
            Toast.makeText(mContext, "" + e, Toast.LENGTH_SHORT).show();
        }
        Toast.makeText(mContext, "" + jsonObject, Toast.LENGTH_SHORT).show();
        if(kode==2){
            return true;
        }else{
            return false;
        }

    }
}
CustomRequest.java

Sudah ditampilkan diatas, dibagian class pendukung.

Package Template

Didalam package ini terdapat constanta untuk endpoint dan beberapa query ke server. Kenapa perlu didefinisikan sendiri, karena jika ada perubahan kedepan, cukup mengganti dibagian constanta saja.

Template.java
package heends.volleycrud.Template;

/**
 * Created by -Andevindo- on 10/8/2015.
 */
public interface Template {

    interface VolleyRetryPolicy{
        int SOCKET_TIMEOUT = 3000;
        int RETRIES = 1;
    }

    interface Query{
        String TAG = "tag";
        String USERNAME_BEFORE = "usernameBefore";
        String USERNAME = "username";
        String PASSWORD = "password";

        String LOGIN = "login";
        String SIGNUP = "signUp";
        String FIND = "find";
        String UPDATE = "update";
        String DELETE = "delete";
    }

}
EndpointAPI.java
package heends.volleycrud.Template;

/**
 * Created by -Andevindo- on 10/8/2015.
 */
public interface EndpointAPI {
    String ANDEVINDO =  "http://andevindo.uphero.com/php/main.php";
}

Isi dari String ANDEVINDO diatas adalah lokasi file main.php diserver. Rubah bagian diatas, jika menggunakan server sendiri.

Package Interface

VolleyInterface.java
package heends.volleycrud.Interface;


import com.android.volley.VolleyError;

import org.json.JSONObject;


/**
 * Created by -Andevindo- on 10/8/2015.
 */
public interface VolleyInterface {
    void onPrepare();
    void onSucces(JSONObject jsonObject);
    void onFailed(VolleyError errorListener);
}

File diatas fungsinya untuk diterapkan diclass-class yang membutuhkan respon dari Volley.

Package Fragment

Berisikan fragment-fragment sebagai sub tampilan dari main activity.

UpdateFragment.java
package heends.volleycrud.Fragment;


import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.VolleyError;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import heends.volleycrud.Interface.VolleyInterface;
import heends.volleycrud.R;
import heends.volleycrud.Template.EndpointAPI;
import heends.volleycrud.Template.Template;
import heends.volleycrud.Utils.JSONParser;
import heends.volleycrud.Utils.VolleyRequest;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class UpdateFragment extends Fragment {

    private EditText mUsernameBefore, mUsernameAfter, mPasswordAfter;
    private Button mFind, mUpdate;
    private VolleyRequest mRequestFind, mRequestUpdate;
    private ProgressBar mProgressFind, mProgressUpdate;
    private LinearLayout mUpdateLayout;
    private JSONParser mJSONParser;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_update, container, false);
        mJSONParser = new JSONParser(getContext());
        mUpdateLayout = (LinearLayout) view.findViewById(R.id.update_layout);

        mRequestFind = new VolleyRequest(new VolleyInterface() {
            @Override
            public void onPrepare() {
                switchButtonProgressFind(true);
                resetLayout();
            }

            @Override
            public void onSucces(JSONObject jsonObject) {
                switchButtonProgressFind(false);
                if (mJSONParser.isSuccess(jsonObject)) {
                    mUpdateLayout.setVisibility(LinearLayout.VISIBLE);
                } else {
                   resetLayout();
                }
            }

            @Override
            public void onFailed(VolleyError errorListener) {
                switchButtonProgressFind(false);
                resetLayout();
                Toast.makeText(getActivity(), "Error : " + errorListener, Toast.LENGTH_SHORT).show();
            }
        });

        mRequestUpdate = new VolleyRequest(new VolleyInterface() {
            @Override
            public void onPrepare() {
                switchButtonProgressUpdate(true);
            }

            @Override
            public void onSucces(JSONObject jsonObject) {
                switchButtonProgressUpdate(false);
                if (mJSONParser.isSuccess(jsonObject)) {
                    resetLayout();
                } else {

                }
            }

            @Override
            public void onFailed(VolleyError errorListener) {
                switchButtonProgressUpdate(false);
                Toast.makeText(getActivity(), "Error : " + errorListener, Toast.LENGTH_SHORT).show();
            }
        });
        mProgressFind = (ProgressBar) view.findViewById(R.id.progress_find);
        mProgressUpdate = (ProgressBar) view.findViewById(R.id.progress_update);
        mUsernameBefore = (EditText) view.findViewById(R.id.username);
        mUsernameAfter = (EditText) view.findViewById(R.id.username_update);
        mPasswordAfter = (EditText) view.findViewById(R.id.password_update);
        mFind = (Button) view.findViewById(R.id.find);
        mFind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Map<String, String> map = new HashMap<>();
                map.put(Template.Query.TAG, Template.Query.FIND);
                map.put(Template.Query.USERNAME, mUsernameBefore.getText().toString());
                mRequestFind.sendPostRequest(EndpointAPI.ANDEVINDO, map);
            }
        });

        mUpdate = (Button) view.findViewById(R.id.update);
        mUpdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Map<String, String> map = new HashMap<>();
                map.put(Template.Query.TAG, Template.Query.UPDATE);
                map.put(Template.Query.USERNAME_BEFORE, mUsernameBefore.getText().toString());
                map.put(Template.Query.USERNAME, mUsernameAfter.getText().toString());
                map.put(Template.Query.PASSWORD, mPasswordAfter.getText().toString());
                mRequestUpdate.sendPostRequest(EndpointAPI.ANDEVINDO, map);
            }
        });
        return view;
    }

    void resetLayout() {
        mUpdateLayout.setVisibility(LinearLayout.GONE);
        mUsernameAfter.setText("");
        mPasswordAfter.setText("");
    }

    void switchButtonProgressFind(boolean isLoading) {
        if (isLoading) {
            mFind.setVisibility(Button.GONE);
            mProgressFind.setVisibility(ProgressBar.VISIBLE);
        } else {
            mFind.setVisibility(Button.VISIBLE);
            mProgressFind.setVisibility(ProgressBar.GONE);
        }
    }

    void switchButtonProgressUpdate(boolean isLoading) {
        if (isLoading) {
            mUpdate.setVisibility(Button.GONE);
            mProgressUpdate.setVisibility(ProgressBar.VISIBLE);
        } else {
            mUpdate.setVisibility(Button.VISIBLE);
            mProgressUpdate.setVisibility(ProgressBar.GONE);
        }
    }

}
SignUpFragment.java
package heends.volleycrud.Fragment;


import android.os.Bundle;

import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.VolleyError;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import heends.volleycrud.Interface.VolleyInterface;
import heends.volleycrud.R;
import heends.volleycrud.Template.EndpointAPI;
import heends.volleycrud.Template.Template;
import heends.volleycrud.Utils.JSONParser;
import heends.volleycrud.Utils.VolleyRequest;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class SignUpFragment extends Fragment implements VolleyInterface{

    private EditText mUsername, mPassword;
    private Button mSignUp;
    private VolleyRequest mRequest;
    private ProgressBar mProgress;
    private JSONParser mJSONParser;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_sign_up, container, false);
        mJSONParser = new JSONParser(getContext());
        mRequest = new VolleyRequest(this);
        mProgress = (ProgressBar)view.findViewById(R.id.progress_sign_up);
        mUsername = (EditText)view.findViewById(R.id.username);
        mPassword = (EditText)view.findViewById(R.id.password);
        mSignUp = (Button)view.findViewById(R.id.sign_up);
        mSignUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Map<String,String> map = new HashMap<>();
                map.put(Template.Query.TAG, Template.Query.SIGNUP);
                map.put(Template.Query.USERNAME, mUsername.getText().toString());
                map.put(Template.Query.PASSWORD, mPassword.getText().toString());
                mRequest.sendPostRequest(EndpointAPI.ANDEVINDO, map);
            }
        });
        return view;
    }

    void switchButtonProgress(boolean isLoading){
        if(isLoading){
            mSignUp.setVisibility(Button.GONE);
            mProgress.setVisibility(ProgressBar.VISIBLE);
        }else{
            mSignUp.setVisibility(Button.VISIBLE);
            mProgress.setVisibility(ProgressBar.GONE);
        }
    }
    @Override
    public void onPrepare() {
        switchButtonProgress(true);
    }

    @Override
    public void onSucces(JSONObject jsonObject) {
        switchButtonProgress(false);
        mJSONParser.isSuccess(jsonObject);
    }

    @Override
    public void onFailed(VolleyError errorListener) {
        switchButtonProgress(false);
        Toast.makeText(getActivity(), "Error : " + errorListener, Toast.LENGTH_SHORT).show();
    }
}
LoginFragment.java
package heends.volleycrud.Fragment;


import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.VolleyError;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import heends.volleycrud.Interface.VolleyInterface;
import heends.volleycrud.R;
import heends.volleycrud.Template.EndpointAPI;
import heends.volleycrud.Template.Template;
import heends.volleycrud.Utils.JSONParser;
import heends.volleycrud.Utils.VolleyRequest;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class LoginFragment extends Fragment implements VolleyInterface{

    private EditText mUsername, mPassword;
    private Button mLogin;
    private VolleyRequest mRequest;
    private ProgressBar mProgress;
    private JSONParser mJSONParser;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_login, container, false);
        mJSONParser = new JSONParser(getContext());
        mRequest = new VolleyRequest(this);
        mProgress = (ProgressBar)view.findViewById(R.id.progress_login);
        mUsername = (EditText)view.findViewById(R.id.username);
        mPassword = (EditText)view.findViewById(R.id.password);
        mLogin = (Button)view.findViewById(R.id.login);
        mLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Map<String,String> map = new HashMap<>();
                map.put(Template.Query.TAG, Template.Query.LOGIN);
                map.put(Template.Query.USERNAME, mUsername.getText().toString());
                map.put(Template.Query.PASSWORD, mPassword.getText().toString());
                mRequest.sendPostRequest(EndpointAPI.ANDEVINDO, map);
            }
        });

        return view;
    }

    void switchButtonProgress(boolean isLoading){
        if(isLoading){
            mLogin.setVisibility(Button.GONE);
            mProgress.setVisibility(ProgressBar.VISIBLE);
        }else{
            mLogin.setVisibility(Button.VISIBLE);
            mProgress.setVisibility(ProgressBar.GONE);
        }
    }


    @Override
    public void onPrepare() {
        switchButtonProgress(true);
    }

    @Override
    public void onSucces(JSONObject jsonObject) {
        switchButtonProgress(false);
        mJSONParser.isSuccess(jsonObject);

    }

    @Override
    public void onFailed(VolleyError errorListener) {
        switchButtonProgress(false);
        Toast.makeText(getActivity(), "Error : " + errorListener, Toast.LENGTH_SHORT).show();
    }
}

DeleteFragment.java

package heends.volleycrud.Fragment;


import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.VolleyError;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import heends.volleycrud.Interface.VolleyInterface;
import heends.volleycrud.R;
import heends.volleycrud.Template.EndpointAPI;
import heends.volleycrud.Template.Template;
import heends.volleycrud.Utils.JSONParser;
import heends.volleycrud.Utils.VolleyRequest;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class DeleteFragment extends Fragment implements VolleyInterface{


    private EditText mUsername;
    private Button mFind, mDelete;
    private VolleyRequest mRequestFind, mRequestDelete;
    private ProgressBar mProgressFind, mProgressDelete;
    private LinearLayout mDeleteLayout;
    private JSONParser mJSONParser;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_delete, container, false);

        mJSONParser = new JSONParser(getContext());
        mDeleteLayout = (LinearLayout)view.findViewById(R.id.delete_layout);

        mRequestFind = new VolleyRequest(new VolleyInterface() {
            @Override
            public void onPrepare() {
                switchButtonProgressFind(true);
                mDeleteLayout.setVisibility(LinearLayout.GONE);
            }

            @Override
            public void onSucces(JSONObject jsonObject) {
                switchButtonProgressFind(false);
                if(mJSONParser.isSuccess(jsonObject)){
                    mDeleteLayout.setVisibility(LinearLayout.VISIBLE);
                }else{
                    mDeleteLayout.setVisibility(LinearLayout.GONE);
                }
            }

            @Override
            public void onFailed(VolleyError errorListener) {
                switchButtonProgressFind(false);
                mDeleteLayout.setVisibility(LinearLayout.GONE);
                Toast.makeText(getActivity(), "Error : " + errorListener, Toast.LENGTH_SHORT).show();
            }
        });

        mRequestDelete = new VolleyRequest(new VolleyInterface() {
            @Override
            public void onPrepare() {
                switchButtonProgressDelete(true);
            }

            @Override
            public void onSucces(JSONObject jsonObject) {
                switchButtonProgressDelete(false);
                mJSONParser.isSuccess(jsonObject);
                mDeleteLayout.setVisibility(LinearLayout.GONE);
            }

            @Override
            public void onFailed(VolleyError errorListener) {
                switchButtonProgressDelete(false);
                Toast.makeText(getActivity(), "Error : " + errorListener, Toast.LENGTH_SHORT).show();
            }
        });
        mProgressFind = (ProgressBar)view.findViewById(R.id.progress_find);
        mProgressDelete = (ProgressBar)view.findViewById(R.id.progress_delete);
        mUsername = (EditText)view.findViewById(R.id.username);
        mFind = (Button)view.findViewById(R.id.find);
        mFind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Map<String,String> map = new HashMap<>();
                map.put(Template.Query.TAG, Template.Query.FIND);
                map.put(Template.Query.USERNAME, mUsername.getText().toString());
                mRequestFind.sendPostRequest(EndpointAPI.ANDEVINDO, map);
            }
        });

        mDelete = (Button)view.findViewById(R.id.delete);
        mDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Map<String, String> map = new HashMap<>();
                map.put(Template.Query.TAG, Template.Query.DELETE);
                map.put(Template.Query.USERNAME, mUsername.getText().toString());
                mRequestDelete.sendPostRequest(EndpointAPI.ANDEVINDO, map);
            }
        });
        return view;
    }

    void switchButtonProgressFind(boolean isLoading){
        if(isLoading){
            mFind.setVisibility(Button.GONE);
            mProgressFind.setVisibility(ProgressBar.VISIBLE);
        }else{
            mFind.setVisibility(Button.VISIBLE);
            mProgressFind.setVisibility(ProgressBar.GONE);
        }
    }

    void switchButtonProgressDelete(boolean isLoading){
        if(isLoading){
            mDelete.setVisibility(Button.GONE);
            mProgressDelete.setVisibility(ProgressBar.VISIBLE);
        }else{
            mDelete.setVisibility(Button.VISIBLE);
            mProgressDelete.setVisibility(ProgressBar.GONE);
        }
    }

    @Override
    public void onPrepare() {

    }

    @Override
    public void onSucces(JSONObject jsonObject) {

    }

    @Override
    public void onFailed(VolleyError errorListener) {

    }
}

Package Application

MyApplication.java
package heends.volleycrud.Application;

import android.app.Application;
import android.content.Context;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class MyApplication extends Application {
    private static MyApplication myApplication;

    @Override
    public void onCreate() {
        super.onCreate();
        myApplication = this;
    }

    public static MyApplication getInstance() {
        return myApplication;
    }

    public static Context getContext() {
        return myApplication.getApplicationContext();
    }
}

Class diatas akan dipanggil pertama kali, ketika program running. Dan class diatas, dibutuhkan oleh VolleySingleton class, untuk mendapatkan Context.

Package Adapter

PagerAdapter.java
package heends.volleycrud.Adapter;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import heends.volleycrud.Fragment.DeleteFragment;
import heends.volleycrud.Fragment.LoginFragment;
import heends.volleycrud.Fragment.SignUpFragment;
import heends.volleycrud.Fragment.UpdateFragment;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class PagerAdapter extends FragmentPagerAdapter {

    private String[] title = {"Login", "SignUp", "Update", "Delete"};

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment;
        if (position == 0) {
            fragment = new LoginFragment();
        } else if (position == 1) {
            fragment = new SignUpFragment();
        } else if (position == 2) {
            fragment = new UpdateFragment();
        } else {
            fragment = new DeleteFragment();
        }
        return fragment;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return title[position];
    }

    @Override
    public int getCount() {
        return title.length;
    }
}

Class diatas sebagai adapter dari ViewPager yang digunakan untuk mengatur sub tampilan di main activity.

Package Acitivity

MainActivity.java
package heends.volleycrud.Activity;

import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;

import heends.volleycrud.Adapter.PagerAdapter;
import heends.volleycrud.R;

/**
 * Created by -Andevindo- on 10/8/2015.
 */

public class MainActivity extends AppCompatActivity {

    private TabLayout mTab;
    private ViewPager mPager;
    private PagerAdapter mAdapter;
    private Toolbar mToolbar;

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

        mToolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
        mTab = (TabLayout)findViewById(R.id.tab);
        mTab.setTabMode(TabLayout.GRAVITY_FILL);
        mPager = (ViewPager)findViewById(R.id.pager);
        mAdapter = new PagerAdapter(getSupportFragmentManager());
        mPager.setAdapter(mAdapter);
        mTab.setupWithViewPager(mPager);



    }
}

Terakhir yang paling penting,

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

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

    <application
        android:name=".Application.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Activity.MainActivity"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Jika ingin menggunakan class-class diatas, saya ingatkan kembali, untuk selalu mengecek nama packagenya. Dan juga untuk memperhatikan penggunaan class lain dalam satu class, karena satu class bisa berkaitan dengan class lain.

Setelah dirun, hasilnya seperti berikut:

device-2015-10-09-004051 device-2015-10-09-004257 device-2015-10-09-004338 device-2015-10-09-004400

Aplikasi ini berjalan lancar di:

  1. Android Studio versi 1.4
  2. Gradle versi 1.3
  3. Min SDK versi 11
  4. Compile SDK versi 23
  5. Build Tools versi 23.0.0
  6. Appcompat-v7  versi 23.0.1
  7. Support Design versi 23.0.1
  8. Volley Library versi 1.0.19

Download Sourcecode Android:

https://drive.google.com/open?id=0B_kqVutLbTK5Qm5HajRieUZ3NVk

Download Sourcecode Webservice:

https://drive.google.com/open?id=0B_kqVutLbTK5SVVBbnpRcWhhSms

Download Apk : (Kemungkinan sudah tidak jalan karena hosting sudah mati)

https://drive.google.com/open?id=0B_kqVutLbTK5LUFRUXNodGZBRkE

Terima kasih kepada:

  1. https://www.iconfinder.com/webalys untuk iconnya