Buku Saku untuk HP Android

Pada jaman dahulu kala, sebelum ada HP, yang ada di saku celana atau saku baju di hampir setiap orang yang non-buta huruf adalah hanya sebuah buku kecil yang bernama 'buku saku' atau bahasa kerén-nya 'buku notes' atau bahasa kerén-nya lagi 'notes book'.
Saya mau mengenang masa lalu sekalian sambil belajar dengan membangun sebuah aplikasi untuk di install ke HP android agar dapat di pakai bagaikan buku saku. Di sini saya tekankan bahwa bukan aplikasinya yang di kedepankan tapi cara membuat aplikasi yang saya mau tularkan. Siapa tahu dengan mengetahui aplikasi sederhana seperti ini, akan dapat memompa semangat dan melahirkan ide untuk membuat aplikasi yang lebih canggih dan di minat pasar. Skalian juga belajar CRUD(Create, Retrieve, Update, Delete) di android.
Sudah cukup banyak aplikasi yang menyerupai buku saku in di pasaran tapi semuanya cukup berat untuk HP, misalnya aplikasi Notepad bisa saja di pakai sebagai buku saku karena bisa juga di pakai untuk membuat catatan kecil tapi setiap kali kita menyimpan data dari notepad di HP maka selalu akan memakan banyak ruang simpan karena harus menyimpan sehalaman notepad walau isinya hanya sebaris tulisan.

Buku Saku yang saya bangun ini hanya akan memiliki judul dan isinya (lihat Gambar 2 dan Gambar 3). Yang akan tampak di halaman depan adalah judulnya saja (lihat Gambar 4), dan ketika di klik pada judul maka akan terlihat isinya (lihat Gambar 3).
Untuk dapat masukan data ke dalam Buku Saku ini, maka di pojok kanan atas layar HP akan di bubuhkan sebuah menu(tombol) dengan nama "Tulis" yang kalau di klik atau di sentuh maka akan membuka halaman baru(kertas baru) yang siap untuk di tulis (lihat Gambar 1). Perhatikan gambar-gambar berikut:
Gambar 1
Gambar 2
Gambar 3
Gambar 4
Gambar 5

Dari segi UI(user interface) Buku Saku ini akan memiliki kriteria sbb:

  1. Ada menu atau tombol untuk membuka halaman baru
  2. Ada pilihan (jenis) data misalnya 'segera' atau hanya 'untuk di ingat' (lihat Gambar 3)
  3. Ada bagian judul (lihat Gambar 2)
  4. Ada bagian isi (lihat Gambar 2)
  5. Ada menu atau tombol untuk bisa simpan data (lihat Gambar 3)
  6. Ada menu atau tombol untuk bisa menghapus data (lihat Gambar 5)
Berdasarkan kriteria-kriteria tersebut, maka halaman depan atau halaman pertama yang muncul di layar HP tentunya adalah sebuah kertas kosong atau halaman kosong atau layar kosong, persis seperti ketika kita membuka buku saku benaran yang belum ada isinya (lihat Gambar 1).
Kertas kosong tersebut akan di representasikan dengan class java tersendiri dan secara exclusive saya menamakan classnya BStampilanDepan.java

Class BStampilanDepan.java adalah logika java untuk halaman depan BukuSakuKu



Logika menamakan class tergantung selera masing-masing developer. BS pada nama class diatas adalah singkatan dari 'buku saku'. hal itu hanya untuk logika pribadi saya saja.

Walau Halaman depan  Buku Saku ini akan nampak kosong, tetapi class BSbagianDepan.java yang merepresentasikan-nya akan di kode-kan dengan cukup padat karena kedepan-nya halaman depan ini tak akan kosong lagi. Halaman depan-nya akan di isi dengan judul-judul dari tulisan yang akan menempatkan diri tampil berjajar baris demi baris, sehingga dengan demikian dapat memudahkan pengguna untuk scrolling mencari tulisan-nya secara cepat.

Oleh karena saya ingin tulisan-nya tampil berjajar baris demi baris maka class BSbagianDepan.java akan menggandeng class ListActivity.java dengan kata kunci extends karena sesuai namanya List = (daftar)perbaris.
Halaman depan juga harus mempunyai kemampuan untuk me-loading(menyimpan dan membuka) data. Untuk itu di perlukan class LoaderManager.java dengan kata kunci implements
Sesuai namanya class LoaderManager.java  adalah bekerja me-load yaitu upload(simpan) dan download(tunjukan data ke halaman). Class ListActivity dan class LoaderManager sudah ada dalam operasi sistim android sehingga kita tinggal memakainya saja dengan menggunakan kata kunci yang telah saya sebutkan di atas.

Saya berasumsi bahwa anda membaca tulisan ini karena anda sudah kenal proses kerja android di eclipse. Berikut adalah isi dari class BSbagianDepan.java yang akan merenda halaman depan aplikasi ini yang saya kasih nama lengkapnya BukuSakuKu

package com.vik_sintus.bukusakuku;
/**
 * Copyright (C) 2013 Vik Sintus Projects
 *
 * Segala kelebihan dan kekurangan di luar tanggung jawab pembuat.
 * Di larang memakai kode ini untuk kepentingan komersial tanpa ijin.
 * Silahkan di pakai untuk kepentingan belajar.
 * vik.sintus@gmail.com
 * http://belajar-android-indonesia.blogspot.com
 * Unless required by applicable law or agreed to in writing, this software
 * is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * 
 * 
 */
import android.app.ListActivity;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import com.vik_sintus.bukusakuku.contentprovider_nya.ContentProviderNya;
import com.vik_sintus.bukusakuku.database_nya.ClassUntukTable;

/*
 * class ini untuk menunjukan data yang telah ada di
 * BukuSakuKu
 * 
 * dan masukan data baru dengan menekan tombol 'Tulis' 
 * Untuk menghapus data yang tak di butuhkan lagi silahkan
 * long press atau sentuh agak lama pada nama data yang 
 * mau di hapus sampai muncul tulisan 'Hapus'
 */

public class BStampilanDepan extends ListActivity implements
    LoaderManager.LoaderCallbacks<Cursor> {
  private static final int ID_HAPUS_DATA = Menu.FIRST + 1;
  // private Cursor cursor;
  private SimpleCursorAdapter adapter_nya;

  
/** di panggil saat membuat activity_nya. */

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.tampilan_depan);
    this.getListView().setDividerHeight(2);
    tampilkanData();// tampil data darimana? lihat private void
    registerForContextMenu(getListView());
  }

  // buat menu 'Tulis' di pojok kanan atas
  @Override
  public boolean onCreateOptionsMenu(Menu menuPembuka) {
    MenuInflater ketikaKlikPadaMenu = getMenuInflater();
    ketikaKlikPadaMenu.inflate(R.menu.untuk_menu_utama, menuPembuka);
    return true;
  }
 
  // ketika membuka halaman baru(kertas kosong) untuk
  // masukanData
  @Override
  public boolean onOptionsItemSelected(MenuItem ketikaMauTulis) {
    switch (ketikaMauTulis.getItemId()) {
    case R.id.menulis_data:
      masukanData();//masukan data yang bagaimana? lihat private void
      return true;
    }
    return super.onOptionsItemSelected(ketikaMauTulis);
  }

  @Override
  public boolean onContextItemSelected(MenuItem itemYangDiKlik) {
    switch (itemYangDiKlik.getItemId()) {
    case ID_HAPUS_DATA:
      AdapterContextMenuInfo informasiMenu = (AdapterContextMenuInfo) itemYangDiKlik
          .getMenuInfo();
      Uri resource_nya = Uri.parse(ContentProviderNya.CONTENT_URI_NYA + "/"
          + informasiMenu.id);
      getContentResolver().delete(resource_nya, null, null);
      tampilkanData();
      return true;
    }
    return super.onContextItemSelected(itemYangDiKlik);
  }
  // simpan data ke bagian isi
  private void masukanData() {
    Intent simpanData = new Intent(this, BSbagianIsi.class);
    startActivity(simpanData);
  }

  // halaman data (yaitu activity kedua) atau halaman bagian
  // dalam atau isi dari buku saku (BSbagianIsi.java) akan terbuka saat mau
  // mengisi data baru atau mengubah data lama
  @Override
  protected void onListItemClick(ListView barisanData, View tampilanData, int letakData, long id) {
    super.onListItemClick(barisanData, tampilanData, letakData, id);
    Intent intent_nya = new Intent(this, BSbagianIsi.class);
    Uri identifikasiSumberData = Uri.parse(ContentProviderNya.CONTENT_URI_NYA + "/" + id);
    intent_nya.putExtra(ContentProviderNya.TIPE_CONTENT_ITEM_NYA, identifikasiSumberData);

    startActivity(intent_nya);
  }

  

  private void tampilkanData() {
    // data mana saja dari database (projection) yang
    // harus di sertakan dalam kolom _id utk tampil di halaman depan
 // sehingga hanya judulnya saja yang tampil di halaman depan
    String[] dataDari = new String[] { ClassUntukTable.KOLOM_JUDUL };
    int[] keTempatTampilNya = new int[] { R.id.tampil_hanya_judul };
    // di load atau di pasang ke halaman baris demi baris
    getLoaderManager().initLoader(0, null, this);
    adapter_nya = new SimpleCursorAdapter(this, R.layout.tampil_perbaris, null, dataDari,
        keTempatTampilNya, 0);

    setListAdapter(adapter_nya);
  }
   // berikut ketika sentuh(long press) pada judul sehingga
   // keluar tombol 'Hapus' agar bisa menghapus data yang 
   // telah di sentuh
  @Override
  public void onCreateContextMenu(ContextMenu menu, View v,
      ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    menu.add(0, ID_HAPUS_DATA, 0, R.string.hapus_judul);
  }

  // membuat sebuah loader baru setelah memanggil metode initLoader ()
  // sehingga me-load lagi judul- judul lain yang tak ingin di hapus dan 
  // tertata kembali agar ruangan bekas tempat judul yang telah di hapus tak
  // bolong(kosong)
  @Override
  public Loader<Cursor> onCreateLoader(int id, Bundle semuaDataYangMauDiLoad) {
    String[] dataManaYangMauDiLoad = { ClassUntukTable.KOLOM_ID, ClassUntukTable.KOLOM_JUDUL };
    CursorLoader cursorLoader = new CursorLoader(this,
        ContentProviderNya.CONTENT_URI_NYA, dataManaYangMauDiLoad, null, null, null);
    return cursorLoader;
  }

  @Override
  public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    adapter_nya.swapCursor(data);
  }

  @Override
  public void onLoaderReset(Loader<Cursor> loader) {
    // datanya tak ada lagi, hapus semua yang berhubungan
 // dengan data tsb
    adapter_nya.swapCursor(null);
  }

}
Perlu saya ingatkan lagi bahwa kode class BStampilanDepan.java tersebut di atas adalah logika internal untuk halaman depan BukuSaku. Ia membutuhkan user interface(UI) agar dapat di lihat dan di sentuh atau di pencet oleh manusia. Berikut adalah beberapa UI-nya.

⇒Lihat pada metode onCrate(); disana di minta bagaimana tampang depan dari aplikasi ini. Tampang depan untuk buku saku yang masih baru, tentunya masih kosong bukan? dan nanti kalau sudah ada isinya, saya ingin isinya itu akan tampil baris demi baris. Untuk menghasilkan itu maka berikut adalah file xml yang saya beri nama tampilan_depan.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

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

    <TextView
        android:id="@android:id/empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tak_ada_isi" />

</LinearLayout>
android:id="@android:id/list" = agar nanti kalau sudah ada catatan di buku sakunya maka akan tampil berjajar dan berbaris.
android:id="@android:id/empty" = kosong ketika belum ada isinya

⇒Lihat pada metode public boolean onCreateOptionsMenu disana minta tampilan menu utama aplikasi ini sehingga dengan demikian saya membuat file xml dengan nama untuk_menu_utama.xml yang terlihat sbb:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menulis_data"
        android:showAsAction="always"
        android:title="Tulis">
    </item>

</menu>
Menu utamanya hanya berisi kata "Tulis" di pojok kanan atas layar HP

Selain kedua halaman xml tsb di atas class BStampilanDepan.java juga membutuhkan pengaturan file saat mengisi data.
⇒Lihat metode private void isilahData();
Perbaris adalah yang paling tepat untuk layar kecil seperti HP sehingga dengan demikian saya membuat file dengan nama tampil_perbaris.xml yang isinya terlihat sbb:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/icon"
        android:layout_width="30dp"
        android:contentDescription="@string/logo"
        android:layout_height="24dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:src="@drawable/logo_kecil" />
    

    <TextView
        android:id="@+id/tampil_hanya_judul"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="6dp"
        android:lines="1"
        android:text="@+id/untuk_baris_judul"
        android:textSize="24dp" />
   

</LinearLayout>

Agar HP tahu halaman mana yang muncul ketika menghidupkan aplikasi, maka class BStampilanDepan ini akan di tampilkan di halaman AndroidManifest.xml nanti saya akan bicarakan AndriodManifest sekarang mari kita bicarakan bagaimana membuat logika java untuk halam isi yaitu halaman yang akan menyimpan tulisan di buku saku secara detail seperti terlihat pada Gambar 3. Secara exclusive saya menamakan class untuk logika halaman isi adalah BSbagianIsi.java

Class BSbagianIsi.java adalah logika java untuk halaman yang menampung isi dari BukSakuKu


Di dalam halaman isi akan tampak segala sesuatu yang menyangkut isi, termasuk judul juga akan nampak disana. Selain itu di sana juga akan ada tombol 'Simpan' dan tombol 'Hapus'. Tadi juga saya singgung sedikit tentang jenis catatan yang mau di masukan kedalam buku saku, misalnya apakah catatan-nya bersifat segera, atau hanya untuk di ingat saja. Sebenarnya hal itu tak begitu penting tapi saya mau melebarkan sayap dalam hal developing aplikasi.
Dengan demikian maka yang akan tampil di bagian utama halaman isi adalah 3 buah objects antara lain

  1.  Bagian jenis tulisan akan menggunakan object 'Spinner'
  2.  Bagian judul akan menggunakan object 'EditText'
  3.  Bagian isi juga menggunakan object 'EditText'

Secara sederhana Spinner = dropdown menu dalam HTML sedangkan EditText = text area
Berikut adalah isi dari class BSbagianIsi.java


package com.vik_sintus.bukusakuku;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.vik_sintus.bukusakuku.contentprovider_nya.ContentProviderNya;
import com.vik_sintus.bukusakuku.database_nya.ClassUntukTable;

/*
 * untuk isi BukuSaku
 * masukan data dan hapus data 
 */
public class BSbagianIsi extends Activity {
  private Spinner utkJenis;
  private EditText utkJudul;
  private EditText utkIsi;

  private Uri identifikasiData;

  @Override
  protected void onCreate(Bundle merendaData) {
    super.onCreate(merendaData);
    setContentView(R.layout.tampilan_bagian_isi);

    utkJenis = (Spinner) findViewById(R.id.jenisnya);
    utkJudul = (EditText) findViewById(R.id.isilah_judulnya);
    utkIsi = (EditText) findViewById(R.id.isilah_isinya);
    Button tombolSimpan = (Button) findViewById(R.id.tombol_simpan);

    Bundle dataTambahan = getIntent().getExtras();

    // lihat dan identifikasikan data pada 
    // instance yg telah di simpan sebelumnya
    identifikasiData = (merendaData == null) ? null : (Uri) merendaData
        .getParcelable(ContentProviderNya.TIPE_CONTENT_ITEM_NYA);

    // atau ambil dari activity yang lain
    if (dataTambahan != null) {
      identifikasiData = dataTambahan
          .getParcelable(ContentProviderNya.TIPE_CONTENT_ITEM_NYA);

      isilahData(identifikasiData);
    }

    tombolSimpan.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        if (TextUtils.isEmpty(utkJudul.getText().toString())) {
          tinggalkanPesanPakaiToast();
        } else {
          setResult(RESULT_OK);
          finish();
        }
      }

    });
  }

  private void isilahData(Uri perkenalkanData) {
    String[] kolomYangDisertakan = { ClassUntukTable.KOLOM_JUDUL,
      ClassUntukTable.KOLOM_ISI, ClassUntukTable.KOLOM_JENIS };
    Cursor cursorNya = getContentResolver().query(perkenalkanData, kolomYangDisertakan, null, null,
        null);
    if (cursorNya != null) {
      cursorNya.moveToFirst();
      String category = cursorNya.getString(cursorNya
          .getColumnIndexOrThrow(ClassUntukTable.KOLOM_JENIS));

      for (int i = 0; i < utkJenis.getCount(); i++) {

        String s = (String) utkJenis.getItemAtPosition(i);
        if (s.equalsIgnoreCase(category)) {
          utkJenis.setSelection(i);
        }
      }

      utkJudul.setText(cursorNya.getString(cursorNya
          .getColumnIndexOrThrow(ClassUntukTable.KOLOM_JUDUL)));
      utkIsi.setText(cursorNya.getString(cursorNya
          .getColumnIndexOrThrow(ClassUntukTable.KOLOM_ISI)));

      // cursornya harus selalu di tutup
      cursorNya.close();
    }
  }

  protected void onSaveInstanceState(Bundle ketikaDiMatikan) {
    super.onSaveInstanceState(ketikaDiMatikan);
    diSimpan();
    ketikaDiMatikan.putParcelable(ContentProviderNya.TIPE_CONTENT_ITEM_NYA, identifikasiData);
  }

  @Override
  protected void onPause() {
    super.onPause();
    diSimpan();
  }

  private void diSimpan() {
    String jenisnya = (String) utkJenis.getSelectedItem();
    String judulnya = utkJudul.getText().toString();
    String isinya = utkIsi.getText().toString();

    // hanya bisa di simpan apabila ada judul dan isinya 
    if (isinya.length() == 0 && judulnya.length() == 0) {
      return;
    }

    ContentValues simpanTulisan = new ContentValues();
    simpanTulisan.put(ClassUntukTable.KOLOM_JENIS, jenisnya);
    simpanTulisan.put(ClassUntukTable.KOLOM_JUDUL, judulnya);
    simpanTulisan.put(ClassUntukTable.KOLOM_ISI, isinya);

    if (identifikasiData == null) {
      // untuk masukan data baru
      identifikasiData = getContentResolver().insert(ContentProviderNya.CONTENT_URI_NYA, simpanTulisan);
    } else {
      // untuk update data
      getContentResolver().update(identifikasiData, simpanTulisan, null, null);
    }
  }

  private void tinggalkanPesanPakaiToast() {
    Toast.makeText(BSbagianIsi.this, "Tulis dulu judul dan isinya",
        Toast.LENGTH_LONG).show();
  }
}


Saya telah mencoba sebisa mungkin untuk menamakan object-object pada class BSbagianIsi.java di atas dengan logika yang sederhana, sehingga kodenya boleh di katakan self-explanatory-lah.

Saya juga telah memutuskan untuk membungkus kedua class di atas dalam satu paket(package) karena kedua class tsb memiliki tipe yang hampir sama, keduanya sama-sama ber-inter-aksi dengan pengguna HP. Nama paketnya nampak pada baris pertama pada kode java com.vik_sintus.bukusakuku. Proses menyimpan class java pada paket sesuai tipe dan kegunaan-nya masing-masing, sering di sebut oleh para ahli coding sebagai 'best practice' dan bahkan akan sangat membantu untuk meringankan beban dalam pengaturan struktur data apabila aplikasinya berkembang menjadi aplikasi besar, dalam arti bobot dan jangkauan pasar.

Oleh karena halaman ini sudah terlalu panjang maka class-class untuk database saya tulis di halaman baru silahkan kesana dengan klik disini

 ........sekarang saya lapar saya pergi makan dulu yah....

No comments:

Post a Comment