Headlines Today

Sudah lama saya pengen nulis ini. Melanjutkan tutorial sebelumnya (bagian 3). Mestinya kita sudah punya file PHP untuk menangani permintaan HTTP GET yang dikirim dari ponsel. Kalau belum nyambung, silakan baca tutorial sebelumnya. Oh ya, jika Anda temukan kode program dalam artikel ini berantakan, tidak masalah. Copy dan paste saja ke Netbeans. Netbeans bisa memformatnya untuk Anda. Cukup klik kanan di source code editor lalu pilih Format.

Dalam artikel kali ini kita akan melakukan:
1. Membuka koneksi HTTP ke server dan mengambil hasilnya
2. Mem-parsing field-field dari String sederhana yang didapat dari Server
3. Menyimpan hasil parsing ke dalam sebuah variabel instan class yang khusus dibuat untuk satu record
4. Menampilkan nilai field-field dalam record di tampilan ponsel
semuanya dengan J2ME.

Yang Anda butuhkan untuk melakukannya adalah:
1. Netbeans (rekomendasi: versi 6.5) dengan tambahan modul J2ME
2. File-file PHP yang telah disiapkan sebelumnya, bersama database MySQL dan web server

Membuat project J2ME dengan Netbeans
Yang perlu Anda lakukan adalah mengklik File | New Project, kemudian dari dialog yang muncul pilih J2ME Project

Berikan nama yang baik, dan seterusnya. Secara default, Anda akan mendapatkan file Main.java yang berupa Visual Midlet (buat jika tidak ada). Dengan Visual Midlet, Anda bisa membuat flow aplikasi J2ME dengan cara drag and drop.

Tambahkan sebuah Form dengan cara klik kanan pada Flow View, pilih New/Add | Form. Drag sebuah flow dari Mobile Device (Midlet) ke form, atau apapun nama yang Anda berikan untuk Form yang baru Anda tambahkan (defaultnya form). Klik kanan pada title bar form, kemudian New/Add | Ok Command dan command-command lain yang Anda butuhkan.

Berikutnya, klik title bar form, kemudian klik Screen View (persis di bagian atas diagram). Di bawah tab-tab nama file.

Pada Screen View, Anda bisa menambahkan beberapa komponen. Untuk contoh kita ini saya tambahkan 5 buah TextField yang masing-masing saya beri nama (variabelnya):
1. textFieldId
2. textFieldName
3. textFieldAddress
4. textFieldBillValue
5. textFieldNotes

Membuat koneksi HTTP
Untuk melakukan koneksi HTTP ke server, kita membutuhkan pengetahuan tentang class dan konsep Thread, class Connector, dan class HttpConnection.

Kita perlu membuat thread baru untuk melakukan koneksi dengan HTTP agar aplikasi kita tidak blocking (terrasa seperti hang) ketika koneksi berjalan. Ya, Anda tahu kan, melakukan koneksi jaringan kadang membutuhkan waktu tertentu.

Class Connector diperlukan untuk membuat object HttpConnection pada J2ME. Begitulah ringkasnya.

import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; /* * To change this template, choose Tools | Templates * and open the template in the editor. */ /** * * @author Amri Shodiq */ public class HttpThread implements Runnable { String command = ""; String[] parameters = null; ThreadListenable parent = null; public HttpThread(String command, String[] parameters, ThreadListenable parent) { // command digunakan untuk menentukan fungsi apa yang // akan dipanggil this.command = command; // parameters digunakan untuk memberikan parameter fungsi tersebut this.parameters = parameters; this.parent = parent; } public void run() { HttpConnection con = null; InputStream is = null; try { // pada contoh ini kebetulan yang dijalankan hanya fungsi READ // yang menggunakan 1 parameter saja // silakan ubah sendiri jika Anda ingin menjalankan fungsi lainnya con = (HttpConnection) Connector.open("http://localhost/Tutorial/function.php?function="+command+"&parameters=" + parameters[0]); con.setRequestMethod(HttpConnection.GET); con.setRequestProperty("Content-Type", "//text plain"); con.setRequestProperty("Connection", "close"); String str = ""; if (con.getResponseCode() == HttpConnection.HTTP_OK) { is = con.openInputStream(); int len = (int) con.getLength(); if (len != -1) { byte incomingData[] = new byte[len]; is.read(incomingData); str = new String(incomingData); // hanya untuk testing System.out.println("String: " + str); // kirim hasilnya ke Midlet parent.setHttpResult(str); } else { ByteArrayOutputStream bytestream = new ByteArrayOutputStream(); int ch; while ((ch = is.read()) != -1) { bytestream.write(ch); } str = new String(bytestream.toByteArray()); // hanya untuk testing System.out.println("String: " + str); // kirim hasilnya ke Midlet parent.setHttpResult(str); bytestream.close(); } } else { System.out.println("Server memberi jawaban tidak OK"); } } catch (IOException ex) { System.out.println(ex.getMessage()); } } }
Perhatikan di atas, kita membuat file HttpThread khusus untuk menangani koneksi HTTP dengan Thread. Pada kasus ini kita menggunakan Thread yang mengimplement interface Runnable (artinya nanti class ini bisa diperlakukan sebagai thread).

Membuat interface ThreadListenable
Perhatikan pada source code di atas, kita menggunakan class ThreadListenable untuk variabel parent. Kepada parent inilah HttpThread akan mengembalikan hasil. Siapakah ThreadListenable? Kita akan mengimplementasikan ThreadListenable untuk Main (Visual Midlet kita) agar sebuah variabel dalam midlet tersebut dapat diupdate oleh HttpThread.

Inilah source code interfacenya:

/** * * @author Amri Shodiq */ public interface ThreadListenable { public void setHttpResult(String someString); }

Membuat class CustomerRecord
Class ini akan kita gunakan sebagai Bean untuk menyimpan record yang kita dapat dari HTTP server. Kode programnya sebagai berikut. Sebentar, saya akan beritahukan satu rahasia untuk Anda. Untuk menulis kode program di bawah ini saya hanya menulis variabel-variabelnya saja (customerId, customerName, dll). Method-methodnya digenerate otomatis oleh Netbeans setelah saya block variabel-variabel yang saya tulis, kemudian klik kanan. Pilih Refactor | Encapsulate Fields. Klik tombol Select All, kemudian klik Refactor. Selesai.
/** * * @author Amri Shodiq */ public class CustomerRecord { private int customerId = 0; private String customerName = ""; private String address = ""; private int billValue = 0; private String billNotes = ""; public CustomerRecord() { } public CustomerRecord(int id, String name, String address, int value, String notes) { this.customerId = id; this.customerName = name; this.address = address; this.billValue = value; this.billNotes = notes; } /** * @return the customerId */ public int getCustomerId() { return customerId; } /** * @param customerId the customerId to set */ public void setCustomerId(int customerId) { this.customerId = customerId; } /** * @return the customerName */ public String getCustomerName() { return customerName; } /** * @param customerName the customerName to set */ public void setCustomerName(String customerName) { this.customerName = customerName; } /** * @return the address */ public String getAddress() { return address; } /** * @param address the address to set */ public void setAddress(String address) { this.address = address; } /** * @return the billValue */ public int getBillValue() { return billValue; } /** * @param billValue the billValue to set */ public void setBillValue(int billValue) { this.billValue = billValue; } /** * @return the billNotes */ public String getBillNotes() { return billNotes; } /** * @param billNotes the billNotes to set */ public void setBillNotes(String billNotes) { this.billNotes = billNotes; } }

Menyelesaikan Main.java (Midlet utama)
Saya menambahkan 2 variabel di dalam Main.java:

private String httpResult = ""; private CustomerRecord currentCustomer = null;

Saya menambahkan beberapa method di dalam Main.java seperti:
1. split
Method ini berfungsi untuk memecah sebuah string berdasarkan separator yang ditentukan dalam parameternya. Kita menggunakannya karena hasil dari HTTP request kita menggunakan format ini.

2. setHttpResult
Method ini digunakan untuk mengupdate variabel httpResult dari HttpThread. Lebih jauh, di akhir method ini juga mengupdate variabel currentCustomer.

3. showCurrentCustomer
Method ini digunakan untuk menampilkan nilai variabel currentCustomer ke dalam Form.

private void showCurrentCustomer() { if (currentCustomer instanceof CustomerRecord) { try { System.out.println("Id: " + currentCustomer.getCustomerId()); System.out.println("Name: " + currentCustomer.getCustomerName()); System.out.println("Address: " + currentCustomer.getAddress()); System.out.println("Bill value: " + currentCustomer.getBillValue()); System.out.println("Bill notes: " + currentCustomer.getBillNotes()); textFieldId.setString(String.valueOf(currentCustomer.getCustomerId())); textFieldName.setString(currentCustomer.getCustomerName()); textFieldAddress.setString(currentCustomer.getAddress()); // textFieldAddress.setString(String.valueOf(currentCustomer.getAddress().trim())); textFieldBillValue.setString(String.valueOf(currentCustomer.getBillValue())); textFieldNotes.setString(currentCustomer.getBillNotes()); } catch (Exception e) { e.printStackTrace(); } } }

private String[] split(String original, String separator) {
Vector nodes = new Vector();
System.out.println("split start...................");
// Parse nodes into vector
int index = original.indexOf(separator);
while (index >= 0) {
nodes.addElement(original.substring(0, index));
original = original.substring(index + separator.length());
index = original.indexOf(separator);
}
// Get the last node
nodes.addElement(original);

// Create splitted string array
String[] result = new String[nodes.size()];
if (nodes.size() > 0) {
for (int loop = 0; loop < style="font-weight: bold;">setHttpResult(String string)
{
httpResult = string;

String[] result = split(string, "##");
if (result[0].equals("0")) {
String[] texts = split(result[1], "||");
for (int i = 0; i < currentcustomer =" new" alert =" new">
Setelah kita memiliki ketiga method di atas, kita perlu menambahkan event yang men-trigger pemanggilan httpThread. Kita tambahkan baris-baris berikut pada method commandAction, pada syarat untuk tombol yang berlabel Edit (pada kasus saya, variabel tombolnya adalah okCommand1).
HttpThread thread = new HttpThread("READ", new String[]{"3"}, this); new Thread(thread).start(); System.out.println("Htp Result: " + httpResult); String[] result = split(httpResult, "##"); //if (result[0].equals("0")) { result = split(result[1], "||"); for (int i = 0; i <> System.out.println(result[i]); }

Baik, mungkin sebaiknya saya share saja seluruh isi file Main.java agar Anda mendapatkan gambaran lebih jelas.

import java.util.Vector; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; /** * @author Amri Shodiq */ public class Main extends MIDlet implements CommandListener, ThreadListenable { private boolean midletPaused = false; private String httpResult = ""; private CustomerRecord currentCustomer = null; // private Form form; private TextField textFieldAddress; private TextField textFieldName; private TextField textFieldId; private TextField textFieldBillValue; private TextField textFieldNotes; private Command okCommand; private Command exitCommand; private Command okCommand1; private Command exitCommand1; private Command okCommand2; // /** * The Main constructor. */ public Main() { } // // // /** * Initilizes the application. * It is called only once when the MIDlet is started. The method is called before the startMIDlet method. */ private void initialize() { // write pre-initialize user code here // write post-initialize user code here } // // /** * Performs an action assigned to the Mobile Device - MIDlet Started point. */ public void startMIDlet() { // write pre-action user code here switchDisplayable(null, getForm()); // write post-action user code here } // // /** * Performs an action assigned to the Mobile Device - MIDlet Resumed point. */ public void resumeMIDlet() { // write pre-action user code here // write post-action user code here } // // /** * Switches a current displayable in a display. The display instance is taken from getDisplay method. This method is used by all actions in the design for switching displayable. * @param alert the Alert which is temporarily set to the display; if null, then nextDisplayable is set immediately * @param nextDisplayable the Displayable to be set */ public void switchDisplayable(Alert alert, Displayable nextDisplayable) { // write pre-switch user code here Display display = getDisplay(); if (alert == null) { display.setCurrent(nextDisplayable); } else { display.setCurrent(alert, nextDisplayable); } // write post-switch user code here } // // /** * Called by a system to indicated that a command has been invoked on a particular displayable. * @param command the Command that was invoked * @param displayable the Displayable where the command was invoked */ public void commandAction(Command command, Displayable displayable) { // write pre-action user code here if (displayable == form) { if (command == exitCommand1) { // write pre-action user code here exitMIDlet(); // write post-action user code here } else if (command == okCommand1) { // write pre-action user code here HttpThread thread = new HttpThread("READ", new String[]{"3"}, this); new Thread(thread).start(); System.out.println("Htp Result: " + httpResult); String[] result = split(httpResult, "##"); //if (result[0].equals("0")) { result = split(result[1], "||"); for (int i = 0; i <> System.out.println(result[i]); } //} // write post-action user code here } else if (command == okCommand2) { // write pre-action user code here // write post-action user code here } } // write post-action user code here } // // /** * Returns an initiliazed instance of form component. * @return the initialized component instance */ public Form getForm() { if (form == null) { // write pre-init user code here form = new Form("Form Input", new Item[] { getTextFieldId(), getTextFieldName(), getTextFieldAddress(), getTextFieldBillValue(), getTextFieldNotes() }); form.addCommand(getOkCommand1()); form.addCommand(getExitCommand1()); form.addCommand(getOkCommand2()); form.setCommandListener(this); // write post-init user code here } return form; } // // /** * Returns an initiliazed instance of textFieldName component. * @return the initialized component instance */ public TextField getTextFieldName() { if (textFieldName == null) { // write pre-init user code here textFieldName = new TextField("Nama", " ", 32, TextField.ANY); // write post-init user code here } return textFieldName; } // // /** * Returns an initiliazed instance of textFieldAddress component. * @return the initialized component instance */ public TextField getTextFieldAddress() { if (textFieldAddress == null) { // write pre-init user code here textFieldAddress = new TextField("Alamat", " ", 100, TextField.ANY); // write post-init user code here } return textFieldAddress; } // // /** * Returns an initiliazed instance of okCommand component. * @return the initialized component instance */ public Command getOkCommand() { if (okCommand == null) { // write pre-init user code here okCommand = new Command("Ok", Command.OK, 0); // write post-init user code here } return okCommand; } // // /** * Returns an initiliazed instance of exitCommand component. * @return the initialized component instance */ public Command getExitCommand() { if (exitCommand == null) { // write pre-init user code here exitCommand = new Command("Exit", Command.EXIT, 0); // write post-init user code here } return exitCommand; } // // /** * Returns an initiliazed instance of textFieldId component. * @return the initialized component instance */ public TextField getTextFieldId() { if (textFieldId == null) { // write pre-init user code here textFieldId = new TextField("Id", " ", 32, TextField.ANY); // write post-init user code here } return textFieldId; } // // /** * Returns an initiliazed instance of okCommand1 component. * @return the initialized component instance */ public Command getOkCommand1() { if (okCommand1 == null) { // write pre-init user code here okCommand1 = new Command("Edit", "Edit", Command.OK, 0); // write post-init user code here } return okCommand1; } // // /** * Returns an initiliazed instance of exitCommand1 component. * @return the initialized component instance */ public Command getExitCommand1() { if (exitCommand1 == null) { // write pre-init user code here exitCommand1 = new Command("Keluar", Command.EXIT, 0); // write post-init user code here } return exitCommand1; } // // /** * Returns an initiliazed instance of okCommand2 component. * @return the initialized component instance */ public Command getOkCommand2() { if (okCommand2 == null) { // write pre-init user code here okCommand2 = new Command("Simpan", Command.OK, 0); // write post-init user code here } return okCommand2; } // // /** * Returns an initiliazed instance of textFieldBillValue component. * @return the initialized component instance */ public TextField getTextFieldBillValue() { if (textFieldBillValue == null) { // write pre-init user code here textFieldBillValue = new TextField("Tagihan", " ", 32, TextField.ANY); // write post-init user code here } return textFieldBillValue; } // // /** * Returns an initiliazed instance of textFieldNotes component. * @return the initialized component instance */ public TextField getTextFieldNotes() { if (textFieldNotes == null) { // write pre-init user code here textFieldNotes = new TextField("Catatan", " ", 32, TextField.ANY); // write post-init user code here } return textFieldNotes; } // /** * Returns a display instance. * @return the display instance. */ public Display getDisplay() { return Display.getDisplay(this); } /** * Exits MIDlet. */ public void exitMIDlet() { switchDisplayable(null, null); destroyApp(true); notifyDestroyed(); } /** * Called when MIDlet is started. * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet. */ public void startApp() { if (midletPaused) { resumeMIDlet(); } else { initialize(); startMIDlet(); } midletPaused = false; } /** * Called when MIDlet is paused. */ public void pauseApp() { midletPaused = true; } /** * Called to signal the MIDlet to terminate. * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released. */ public void destroyApp(boolean unconditional) { } private void showCurrentCustomer() { if (currentCustomer instanceof CustomerRecord) { try { System.out.println("Id: " + currentCustomer.getCustomerId()); System.out.println("Name: " + currentCustomer.getCustomerName()); System.out.println("Address: " + currentCustomer.getAddress()); System.out.println("Bill value: " + currentCustomer.getBillValue()); System.out.println("Bill notes: " + currentCustomer.getBillNotes()); textFieldId.setString(String.valueOf(currentCustomer.getCustomerId())); textFieldName.setString(currentCustomer.getCustomerName()); textFieldAddress.setString(currentCustomer.getAddress()); // textFieldAddress.setString(String.valueOf(currentCustomer.getAddress().trim())); textFieldBillValue.setString(String.valueOf(currentCustomer.getBillValue())); textFieldNotes.setString(currentCustomer.getBillNotes()); } catch (Exception e) { e.printStackTrace(); } } } public void setHttpResult(String string) { httpResult = string; String[] result = split(string, "##"); if (result[0].equals("0")) { String[] texts = split(result[1], "||"); for (int i = 0; i <> System.out.println(i + ". " + texts[i]); } currentCustomer = new CustomerRecord(Integer.parseInt(texts[0]), texts[1], texts[2], Integer.parseInt(texts[3]), texts[4]); showCurrentCustomer(); } else { Alert alert = new Alert("Ada yang tidak beres."); alert.setTimeout(Alert.FOREVER); Display.getDisplay(this).setCurrent(alert); } } private String[] split(String original, String separator) { Vector nodes = new Vector(); System.out.println("split start..................."); // Parse nodes into vector int index = original.indexOf(separator); while (index >= 0) { nodes.addElement(original.substring(0, index)); original = original.substring(index + separator.length()); index = original.indexOf(separator); } // Get the last node nodes.addElement(original); // Create splitted string array String[] result = new String[nodes.size()]; if (nodes.size() > 0) { for (int loop = 0; loop <> result[loop] = (String) nodes.elementAt(loop); //System.out.println(result[loop]); } } return result; } }

Selamat mencoba.

Featured Stories