Tutorial ini adalah pengembangan dari tutorial sebelumnya tentang membuat location based services di Android menggunakan Maps API v2. Pada tutorial kali ini kita akan mengimplementasikan fitur Check-In pada aplikasi location based services tersebut. Check-in ini berfungsi seperti aplikasi Foursquare, hanya saja bersifat private sehingga cuma kalian yang bisa melihat tempat-tempat yang sudah pernah kalian kunjungi. Lokasi tempat-tempat yang pernah kalian kunjungi akan ditampilkan pada peta menggunakan Android Maps API V2. Tutorial mengenai implementasi check in ini akan dibagi menjadi 3 tahap.

Oke sebelum kalian mencoba tutorial ini sangat disarankan untuk membaca postingan-postingan tentang Android Maps API v2 sebelumnya.

Pre-requisites :

  1. Membuat Location Based Service app menggunakan Android Maps API v2
  2. Panduan lengkap Database SQLite Android
  3. Panduan lengkap Android Maps API SDK v2

Add Check-In

Pada tutorial sebelumnya kita telah belajar tentang bagaimana mendapatkan lokasi pengguna menggunakan GPS. Sekarang kita akan belajar cara menyimpan data latitude dan longitude tersebut ke dalam database SQLite Android. Untuk proses transaksi ke database-nya kita akan menggunakan teknik MVC (Model View Controller).

Sekarang, buka kembali project yang telah kalian buat pada tutorial LBS sebelumnya, di situ kita akan menambahkan beberapa kelas baru. Masing-masing kelas tersebut adalah :

  • DBDataSource.java, berfungsi sebagai controller untuk memanipulas data pada database, seperti insert, read dan delete data.
  • CheckInActivity..java; berfungsi sebagai interface/view tempat kita memasukkan data check-in.
  • DBLokasi.java; berfungsi sebagai model objek lokasi.
  • DBMapsHelper.java; berfungsi sebagai SQLite helper, kelas ini menyimpan informasi seperti nama tabel, sintaks SQL untuk create tabel dan sebagainya.

Kemudian beberapa file XML baru yang harus ditambahkan adalah sebagai berikut:

  • activity_checkin.xml; layout untuk tampilan CheckInActivity.
  • fragment_dialog_checkin.xml; layout untuk check-in dialog.
  • fragment_dialog_datashow.xml; layout untuk menampilkan data ketika marker diklik
  • layout_check_in_item.xml; layout sederhana untuk item pada listview.

Oke, pertama-tama kita akan membuat kelas CheckInActivity.java, untuk itu kita akan membuat layoutnya terlebih dahulu. CheckInActivity akan menggunakan ListView untuk menampilkan daftar check-in yang sudah pernah dimasukkan. Di layout ini juga ada tombol check-in yang langsung berfungsi untuk memasukkan koordinat ke dalam database. Dan juga tombol untuk delete semua data, dan tombol untuk memetakan semua lokasi check-in ke Maps.

activity_checkin.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    <TextView
        android:id="@+id/textcheckin"
        android:layout_width="wrap_content"
       	android:layout_height="wrap_content"
       	android:text="check in di sini?"
       	android:layout_gravity="center_horizontal"
       	android:background="#ccc"
       	/>
<LinearLayout
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" > 

   <Button
       android:id="@+id/bt_checkin"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Check-in"
       />
   <Button
       android:id="@+id/bt_showmap"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Petakan semua lokasi"
       />
   <Button
       android:id="@+id/bt_delete"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Delete all"
       />

</LinearLayout>
<ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        />

</LinearLayout>

fragment_dialog_checkin.xml

Setelah layout selesai kita set, kita akan membuat SQLite helper class yang bernama DBMapsHelper.java. Kelas ini merupakan inheritance (extends) dari kelas SQLiteOpenHelper, berisi informasi tentang tabel database yang ingin kita buat, seperti:

  • TABLE_NAME : nama table
  • COLUMN_ID : kolom primary key pada tabel
  • COLUMN_LAT : kolom untuk menyimpan data latitude
  • COLUMN_LONG : kolom untuk menyimpan data longitude
  • COLUMN_NAMA : kolom untuk menyimpan data nama tempat
  • db_version : versi dari database
  • db_name : nama dari database file (.db)

Kemudian di kelas ini juga terdapat SQL command dalam bentuk string(db_create), yang berfungsi untuk membuat database baru, dan mengupgrade apabila ada database baru. Copy pastekan kode berikut ini ke dalam kelas tersebut DBMapsHelper.java :

package id.web.twoh.twohmaps.database;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

@SuppressWarnings("unused")
public class DBMapsHelper extends SQLiteOpenHelper{

	public static final String TABLE_NAME = "data_lokasi";
	public static final String COLUMN_ID = "_id";
	public static final String COLUMN_LAT = "lat";
	public static final String COLUMN_LONG = "long";
	public static final String COLUMN_NAMA = "nama";
	private static final String db_name ="lokasi.db";
	private static final int db_version=1;

	// Database creation sql statement
	private static final String db_create = "create table "
	      + TABLE_NAME + "("
	      + COLUMN_ID +" integer primary key autoincrement, "
	      + COLUMN_LAT+ " varchar(50) not null, "
	      + COLUMN_NAMA+ " varchar(255) not null, "
	      + COLUMN_LONG+ " varchar(50) not null);";

	public DBMapsHelper(Context context) {
		super(context, db_name, null, db_version);

	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(db_create);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		Log.w(DBMapsHelper.class.getName(),"Upgrading database from version " + oldVersion + " to "
	            + newVersion + ", which will destroy all old data");
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
	    onCreate(db);

	}

}

Setelah helper, kita akan membuat model untuk object lokasi yang akan kita masukkan ke dalam database. Kelas ini bernama DBLokasi.java, DBLokasi mempunyai atribut berupa, lat (latitude), lng (longitude), dan id (primary key). Dan juga beberapa methods yang berfungsi sebagai getter dan setter. Ada satu method toString() yang nantinya akan digunakan untuk menampilkan info pada tampilan ListView. Berikut adalah kodenya :

DBLokasi.java

package id.web.twoh.twohmaps.model;

import java.io.Serializable;

public class DBLokasi implements Serializable{

	/**
	 *
	 */
	private static final long serialVersionUID = -151607691806704480L;
	private long id;
	private String lat;
	private String lng;
	private String nama;
	private double latD;
	private double lngD;

	public DBLokasi()
	{

	}

	public long getId() {
	    return id;
	  }

	  public void setId(long id) {
	    this.id = id;
	  }

	  // Will be used by the ArrayAdapter in the ListView
	  @Override
	  public String toString() {
	    return "("+id+")"+" Nama : "+nama+" "+" ("+lat+" , "+lng+")";
	  }

	public String getLat() {
		return lat;
	}

	public void setLat(String lat) {
		this.lat = lat;
	}

	public String getLng() {
		return lng;
	}

	public void setLng(String lng) {
		this.lng = lng;
	}

	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	public String getNama() {
		return nama;
	}

	public void setNama(String nama) {
		this.nama = nama;
	}

	public double getLatD() {
		latD = Double.parseDouble(lat);
		return latD;
	}

	public void setLatD(double latD) {
		this.latD = latD;
	}

	public double getLngD() {
		lngD = Double.parseDouble(lng);
		return lngD;
	}

	public void setLngD(double lngD) {
		this.lngD = lngD;
	}
}

Kemudian, kita akan membuat class controller-nya bernama DBDataSource.java, kelas ini yang berperan penting dalam proses manipulasi data/CRUD. Di kelas ini, methods yang berfungsi untuk membuat lokasi baru, memasukkan lokasi ke dalam database, mendelete lokasi dan lain sebagainya diimplementasikan. Cara kerjanya, awalnya kelas ini akan membuat sebuah database baru dengan cara menginstanstiasi kelas DBMapsHelper, dan mengambil database dari sana. Kemudian database itulah yang nantinya akan dimanipulasi pada saat transaksi data. Penjelasan lebih lanjut ada pada komen di source code :

DBDataSource.java

package id.web.twoh.twohmaps.database;

import id.web.twoh.twohmaps.model.DBLokasi;

import java.util.ArrayList;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

public class DBDataSource {

  // Inisialisasi database fields
  private SQLiteDatabase database;
  private DBMapsHelper dbHelper;

  // Ambil konstanta
  private String[] allColumns = { DBMapsHelper.COLUMN_ID,
      DBMapsHelper.COLUMN_LAT, DBMapsHelper.COLUMN_LONG, DBMapsHelper.COLUMN_NAMA };

  // Menggunakan DBMapsHelper yang diiinisialisasi pada konstruktor
  public DBDataSource(Context context) {
    dbHelper = new DBMapsHelper(context);
  }

  // Mengambil sebuah database yang bisa digunakan
  public void open() throws SQLException {
    database = dbHelper.getWritableDatabase();
  }

  public void close() {
    dbHelper.close();
  }

  // Method yang berfungsi untuk membuat lokasi baru dan memasukkannya ke dalam database
  public DBLokasi createLokasi(DBLokasi lokasi) {
    ContentValues values = new ContentValues();
    values.put(DBMapsHelper.COLUMN_LAT, lokasi.getLat());
    values.put(DBMapsHelper.COLUMN_LONG, lokasi.getLng());
    values.put(DBMapsHelper.COLUMN_NAMA, lokasi.getNama());
    long insertId = database.insert(DBMapsHelper.TABLE_NAME, null,
        values);
    Cursor cursor = database.query(DBMapsHelper.TABLE_NAME,
        allColumns, DBMapsHelper.COLUMN_ID + " = " + insertId, null,
        null, null, null);
    cursor.moveToFirst();
    DBLokasi newLokasi = cursorToLokasi(cursor);
    cursor.close();

    return newLokasi;
  }

  // Method yang berfungsi untuk menghapus lokasi berdasarkan ID
  public void deleteLokasi(DBLokasi lokasi) {
    long id = lokasi.getId();
    System.out.println("Lokasi deleted with id: " + id);
    database.delete(DBMapsHelper.TABLE_NAME, DBMapsHelper.COLUMN_ID
        + " = " + id, null);
  }

  // Method yang berfungsi untuk menghapus semua data lokasi yang tersimpan
  public void deleteAllLokasi()
  {
	  database.execSQL("DELETE FROM "+ DBMapsHelper.TABLE_NAME);
  }

  // Method yang berfungsi untuk mengambil semua lokasi
  public ArrayList<DBLokasi> getAllLokasi() {
    ArrayList<DBLokasi> daftarLokasi = new ArrayList<DBLokasi>();

    Cursor cursor = database.query(DBMapsHelper.TABLE_NAME,
        allColumns, null, null, null, null, null);

    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
      DBLokasi lokasi = cursorToLokasi(cursor);
      daftarLokasi.add(lokasi);
      cursor.moveToNext();
    }
    // Make sure to close the cursor
    cursor.close();
    return daftarLokasi;
  }

  // method yang berfungsi untuk mengambil data lokasi baru berdasarkan ID
  public DBLokasi getLokasi(int id)
  {
	  DBLokasi lokasi = new DBLokasi();

	  Cursor cursor = database.query(DBMapsHelper.TABLE_NAME, allColumns, "_id ="+id, null, null, null, null);
	  cursor.moveToFirst();
	  lokasi = cursorToLokasi(cursor);
	  cursor.close();
	  return lokasi;
  }

  // Method yang berfungsi untuk membuat sebuah objek lokasi baru yang nantinya akan dimasukkan ke dalam database
  private DBLokasi cursorToLokasi(Cursor cursor) {

	  DBLokasi lokasi = new DBLokasi();
	  //Log.v("info", "The getLONG "+cursor.getLong(0));
      //Log.v("info", "The setLatLng "+cursor.getString(1)+","+cursor.getString(2)+cursor.getString(3)+cursor.getString(4)+cursor.getString(5)+cursor.getString(6)+cursor.getString(7));
	  lokasi.setId(cursor.getLong(0));
	  lokasi.setLat(cursor.getString(1));
	  lokasi.setLng(cursor.getString(2));
	  lokasi.setNama(cursor.getString(3));
	  return lokasi;
  }
}

Yups, setelah semuanya lengkap, sekarang kita akan membuat kelas terakhir yang berfungsi sebagai view, bernama CheckInActivity.java. Kelas ini berfungsi sebagai interface yang akan menampilkan data checkin ke dalam ListView.

Oh iya, sebelum membuat kelas ini, kita pertama-tama harus memodifikasi main class yang bernama MainActivity.java (lihat file di GitHub), kita akan tambahkan intent sehingga tombol checkin pada main menu dapat berfungsi. Yaitu pada method berikut :

	    public void switchToCheckIn()
	    {

	    	Intent i = new Intent(getActivity(), CheckInActivity.class);
	    	Bundle b = new Bundle();
	    	if(location!=null)
	    	{
	    	b.putDouble("longitude", location.getLongitude());
	    	b.putDouble("latitude", location.getLatitude());
	    	Log.v("info", "The lat "+location.getLatitude());
	        Log.v("info", "The lng "+location.getLongitude());
	        i.putExtras(b);
	    	startActivity(i);
	    	}else
	    	{
	    		Toast.makeText(getActivity(), "Nyalakan lokasimu", Toast.LENGTH_LONG).show();
	    	}
	    }

Dan tambahkan juga kelas ChekckInActivity ke dalam daftar Activity pada AndroidManifest.xml (lihat file di GitHub).

CheckInActivity.java

package id.web.twoh.twohmaps;

import java.util.ArrayList;

import id.web.twoh.twohmaps.R;
import id.web.twoh.twohmaps.database.DBDataSource;
import id.web.twoh.twohmaps.model.DBLokasi;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class CheckInActivity extends ListActivity implements OnItemLongClickListener{

	private TextView tvCheckin;
	private DBDataSource dataSource;
	private Button btCheck;
	private Button btShowAll;
	private Button btDelete;
	private double lat,lng;
	private ArrayList<DBLokasi> values;
	private ArrayAdapter<DBLokasi> adapter;
	ListView lv;
	public static final String TAG = CheckInActivity.class.getSimpleName();

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

		dataSource = new DBDataSource(this);
		dataSource.open();
		values = dataSource.getAllLokasi();

		btCheck = (Button)findViewById(R.id.bt_checkin);
		btDelete = (Button) findViewById(R.id.bt_delete);
		btShowAll = (Button)findViewById(R.id.bt_showmap);
		tvCheckin = (TextView) findViewById(R.id.textcheckin);

		btDelete.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				dataSource.deleteAllLokasi();
				adapter.clear();
				adapter.notifyDataSetChanged();
				Toast.makeText(CheckInActivity.this, "All data deleted", Toast.LENGTH_SHORT).show();
			}
		});

		btCheck.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(CheckInActivity.this, "checked in", Toast.LENGTH_LONG);
				final Dialog dialog = new Dialog(CheckInActivity.this);
				dialog.setTitle("Input Data Checkin");
				dialog.setContentView(R.layout.fragment_dialog_checkin);
				TextView text = (TextView)dialog.findViewById(R.id.tv_koordinat);
				Button btSave =  (Button) dialog.findViewById(R.id.bt_checkin_save);
				Button btCancel = (Button) dialog.findViewById(R.id.bt_checkin_cancel);
				final EditText etNama = (EditText) dialog.findViewById(R.id.et_nama);
				text.setText("Masukkan data check-in di koordinat ("+lat+","+lng+") : ");

				btCancel.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						dialog.cancel();
					}
				});
				btSave.setOnClickListener(new OnClickListener() {

					@Override
					public void onClick(View v) {
						DBLokasi lokasi = null;
						DBLokasi lokasiTemp = new DBLokasi();
						lokasiTemp.setLat(lat+"");
						lokasiTemp.setLng(lng+"");

						lokasiTemp.setNama(etNama.getText().toString());						

						lokasi = dataSource.createLokasi(lokasiTemp);
						if(lokasi!=null)
						{
							adapter.add(lokasi);
							adapter.notifyDataSetChanged();
						}
						dialog.cancel();
					}
				});
				dialog.show();
			}
		});

		btShowAll.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// lihat di postingan selanjutnya
			}
		});

		Bundle b = this.getIntent().getExtras();
		lat = b.getDouble("latitude");
		lng = b.getDouble("longitude");
		tvCheckin.setText("Ingin check-in di koordinat berikut ? "+lat+","+lng);

		dataSource = new DBDataSource(this);
		dataSource.open();

		values = dataSource.getAllLokasi();

		adapter = new ArrayAdapter<DBLokasi>(this,R.layout.layout_checkin_item, values);
		setListAdapter(adapter);
		lv = getListView();
		lv.setOnItemLongClickListener(new OnItemLongClickListener() {

			@Override
			public boolean onItemLongClick(AdapterView<?> parent, View view,
					int position, long id) {

					DBLokasi lokTemp = adapter.getItem(position);
					dataSource.deleteLokasi(lokTemp);
					Toast.makeText(CheckInActivity.this, "location has been deleted", Toast.LENGTH_SHORT).show();
					adapter.remove(lokTemp);
					adapter.notifyDataSetChanged();

				return true;
			}
		});
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		super.onListItemClick(l, v, position, id);

		DBLokasi lokasi = dataSource.getLokasi((int)adapter.getItem(position).getId());
		if(lokasi!=null)
			// lihat di postingan selanjutnya
		else
			Toast.makeText(this, "location is null", Toast.LENGTH_LONG).show();
	}

	@Override
	public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
		DBLokasi lokasi = dataSource.getLokasi(position+1);
		if(lokasi!=null)
		{
			dataSource.deleteLokasi(lokasi);
			Toast.makeText(CheckInActivity.this, "location has been deleted", Toast.LENGTH_SHORT).show();
			adapter.remove(lokasi);
			adapter.notifyDataSetChanged();
		}else
			Toast.makeText(CheckInActivity.this, "location is null", Toast.LENGTH_SHORT).show();

		return false;
	}

}

Pada aplikasi TWOH Maps V2 ini kita bisa melakukan pengecekan GPS apakah aktif atau tidak. Karena pada versi sebelumnya yang tidak melakukan pengecekan, akan terjadi error apabila kita klik View On Map/Get Location, padahal GPS mati. Koordinat pada peta murni didapat dari GPS.

Kemudian ada fungsionalitas tambahan pada kelas CheckInActivity.java, yaitu untuk melakukan penghapusan data. Untuk menghapus semua data bisa menggunakan tombol “Delete All”, dan untuk menghapus data satu persatu tinggal lakukan long click pada list item untuk menghapus data check-in yang diinginkan.

Demo

Oke, halaman awalnya masih sama seperti pada aplikasi LBS di tutorial sebelumnya :p :

TWOH Maps v2Tampilan Awal TWOH Maps v2

Setelah itu klik tombol Check-In dan kita akan masuk ke tampilan check-in menu dimana sudah ada satu lokasi di sana :

Tampilan halaman check-in :pTampilan halaman check-in :p

Coba kita tambahkan satu lokasi lagi :D. Klik tombol Check-In dan akan muncul dialog dimana kita bisa memasukkan nama lokasi :

Masukkan nama tempatMasukkan nama tempat

Klik save, dan lokasi pun akan muncul pada daftar check-in:

Ada 2 data check-inAda 2 data check-in

Lakukan long-click pada listview item untuk menghapus lokasi :

Hapus satu dataHapus satu data

Kemudian klik tombol “Delete All” untuk menghapus lokasi :). Inilah tampilan halaman Check-in dengan lokasi yang kosong.

hapus semua dataHapus semua data Check-In

Conclusion

Kira-kira seperti itu hal-hal yang perlu ditambahkan. Tutorial selanjutnya adalah untuk menampilkan lokasi yang sudah tersimpan di SQLite ke dalam peta.

Atau kalau kalian ingin mencoba meng-oprek-nya sendiri, bisa download project TWOH-Maps v2 pada repositori GitHub saya.

Jangan sungkan untuk bertanya lewat komentar atau di forum apabila ada yang kurang jelas ! Semoga membantu 😀



Download aplikasi kami di Google Play Store