Membuat Aplikasi Android Pencarian Kode POS

Membuat Aplikasi Android Pencarian Kode POS

Tutorial membuat aplikasi android untuk mencari kode POS indonesia. Dulu saya sempat membuat aplikasi android tapi menggunakan javascript Framework7 + Cordova, nah sekarang saya akan share versi java dibuat di android studio.

Ok langsung saja berikut database kodeposnya yang sudah saya simpan di firebase secara publik jadi biasa digunakan oleh siapa saja. Endpoint:

  1. Daftar propinsi

    https://kodepos-2d475.firebaseio.com/list_propinsi.json?print=pretty

  2. Daftar kota/kabupaten

    https://kodepos-2d475.firebaseio.com/list_kotakab/{key propinsi}.json?print=pretty

  3. Daftar kecamatan, kelurahan & kodepos

    https://kodepos-2d475.firebaseio.com/kota_kab/{key kota}.json?print=pretty

Pertama-tama kita buka android studionya trus create new project, lalu buat file2, class2 seperti digambar:

bachors.com

  1. dimens.xml
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <dimen name="margin_16dp">16dp</dimen>
    </resources>
  2. activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout 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"
        tools:context=".MainActivity">

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

    </android.support.constraint.ConstraintLayout>
  3. activity_propinsi.xml masih sama dengan activity_main.xml
    tools:context=".PropinsiActivity">
  4. list_daerah.xml untuk menampilkan daftar propinsi dan kota.
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:padding="@dimen/margin_16dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/name"
            android:freezesText="true"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            style="@style/TextAppearance.AppCompat.Subhead" />

    </LinearLayout>
  5. activity_kota.xml EditText untuk filter.
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout 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"
        tools:context="com.bachors.kodepos.KotaActivity">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">

            <EditText android:id="@+id/filter"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:padding="@dimen/margin_16dp"
                android:hint="Filter" />

            <ListView
                android:id="@+id/list_pos"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>

    </android.support.constraint.ConstraintLayout>
  6. list_pos.xml untuk menampilkan data kecamatan, kelurahan dan kodepos
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:padding="@dimen/margin_16dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

            <TextView
                android:id="@+id/kecamatan"
                android:freezesText="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                style="@style/TextAppearance.AppCompat.Subhead" />

            <TextView
                android:id="@+id/kodepos"
                android:freezesText="true"
                style="@style/TextAppearance.AppCompat.Subhead"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/colorPrimary"
                android:gravity="end" />

        </LinearLayout>

        <TextView
            android:id="@+id/kelurahan"
            android:freezesText="true"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
  7. Karena data jsonnya cukup sederhana dan berbentuk flat, keynya juga bersifat dinamis
    {
      "p1" : "Bali",
      "p10" : "Jawa Tengah",
      "p11" : "Jawa Timur",
      "p12" : "Kalimantan Barat",
      "p13" : "Kalimantan Selatan",
      "p14" : "Kalimantan Tengah",
      "p15" : "Kalimantan Timur",
      "p16" : "Kalimantan Utara",
      "p17" : "Kepulauan Riau",
      ...
    }
    
    jadi saya menggunakan cara ini yang saya temukan di tutorial http://www.androidhive.info/2012/01/android-json-parsing-tutorial/, tidak menggunakan librari seperti retrofit, volley atau yg lainnya. HttpHandler.java:
    public class HttpHandler {

        private static final String TAG = HttpHandler.class.getSimpleName();

        public HttpHandler() {
        }

        public String makeServiceCall(String reqUrl) {
            String response = null;
            try {
                URL url = new URL(reqUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                // read the response
                InputStream in = new BufferedInputStream(conn.getInputStream());
                response = convertStreamToString(in);
            } catch (MalformedURLException e) {
                Log.e(TAG, "MalformedURLException: " + e.getMessage());
            } catch (ProtocolException e) {
                Log.e(TAG, "ProtocolException: " + e.getMessage());
            } catch (IOException e) {
                Log.e(TAG, "IOException: " + e.getMessage());
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
            return response;
        }

        private String convertStreamToString(InputStream is) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();

            String line;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append('\n');
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return sb.toString();
        }
    }
  8. MainActivity.java mengambil data json daftar propinsi lalu menampilkannya di listview list_daerah.xml menggunakan SimpleAdapter.
    public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

        private String TAG = MainActivity.class.getSimpleName();

        private ProgressDialog pDialog;
        private ListView lv;

        // URL to get propinsi list JSON
        final static String url = "https://kodepos-2d475.firebaseio.com/list_propinsi.json";

        ArrayList<HashMap<String, String>> posList;

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

            // menampung data propinsi
            posList = new ArrayList<>();

            // listview untuk menampilkan daftar propinsi
            lv = (ListView) findViewById(R.id.list_pos);
            lv.setOnItemClickListener(this);

            // Get JSON data
            new GetPost().execute();
        }

        // Async task class to get json by making HTTP call
        private class GetPost extends AsyncTask<Void, Void, Void> {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                // Showing progress dialog
                pDialog = new ProgressDialog(MainActivity.this);
                pDialog.setMessage("Please wait...");
                pDialog.setCancelable(false);
                pDialog.show();

            }

            @Override
            protected Void doInBackground(Void... arg0) {
                HttpHandler sh = new HttpHandler();

                // Making a request to url and getting response
                String jsonStr = sh.makeServiceCall(url);

                Log.e(TAG, "Response from url: " + jsonStr);

                if (jsonStr != null) {
                    try {
                        JSONObject jsonObj = new JSONObject(jsonStr);

                        // Parser flat object
                        Iterator<String> iter = jsonObj.keys();
                        while (iter.hasNext()) {
                            String key = iter.next();
                            try {
                                Object value = jsonObj.get(key);
                                String nama = value.toString();

                                // tmp hash map for single GetPost
                                HashMap<String, String> pos = new HashMap<>();

                                // adding each child node to HashMap key => value
                                pos.put("name", nama);
                                pos.put("idp", key);

                                // adding pos to pos list
                                posList.add(pos);

                            } catch (JSONException e) {
                                // Something went wrong!
                            }
                        }
                    } catch (final JSONException e) {
                        Log.e(TAG, "Json parsing error: " + e.getMessage());
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(getApplicationContext(),
                                        "Data tidak ada.",
                                        Toast.LENGTH_LONG)
                                        .show();
                            }
                        });

                    }
                } else {
                    Log.e(TAG, "Couldn't get json from server.");
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(getApplicationContext(),
                                    "Terjadi kesalahan coba lain waktu.",
                                    Toast.LENGTH_LONG)
                                    .show();
                        }
                    });

                }

                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
                super.onPostExecute(result);
                // Dismiss the progress dialog
                if (pDialog.isShowing())
                    pDialog.dismiss();

                // Sorting a-z
                Collections.sort(posList, new Comparator<HashMap< String,String >>() {

                    @Override
                    public int compare(HashMap<String, String> lhs,
                                       HashMap<String, String> rhs) {
                        return lhs.get("name").compareTo(rhs.get("name"));
                    }
                });

                // Updating parsed JSON data into ListView
                ListAdapter adapter = new SimpleAdapter(
                        MainActivity.this, posList,
                        R.layout.list_daerah, new String[]{"name"}, new int[]{R.id.name});

                lv.setAdapter(adapter);
            }

        }

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // mengambil idp & name dari list yang kita click
            String idp = posList.get(position).get("idp");
            String name = posList.get(position).get("name");

            // mengirim parameter idp & name ke PropinsiActivity
            Intent intent = new Intent(MainActivity.this, PropinsiActivity.class);
            intent.putExtra("idp", posList.get(position).get("idp"));
            intent.putExtra("name", posList.get(position).get("name"));
            startActivity(intent);
        }

    }

    bachors.com

  9. PropinsiActivity.java sama seperti MainActivity.java tinggal merubah url dan activitynya.
    ...
    private static String url;
    ...

    protected void onCreate(Bundle savedInstanceState) {
        ...
        
        Bundle b = getIntent().getExtras();
        // get id propinsi
        url = "https://kodepos-2d475.firebaseio.com/list_kotakab/" + b.getString("idp") + ".json";

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        ActionBar actionBar = getSupportActionBar();
        // set toolbar title
        actionBar.setTitle(b.getString("name"));
        
        ...
    }

    ...

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
            finish();
            return true;
            default:
            return super.onOptionsItemSelected(item);
        }
    }

    bachors.com

  10. KotaActivity.java berbeda dengan MainActivity.java dan PropinsiActivity.java data jsonnya berbentuk array dan ditampilkan di list_kota.xml dan ada proses untuk memfilter listview berdasarkan nama kecamatan atau kelurahan karena datanya banyak.
    public class KotaActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

        ...
        
        // array untuk menampung data filter
        ArrayList<HashMap<String, String>> tmpList;
        
        ...

        @Override
        protected void onCreate(Bundle savedInstanceState) {
        
            ...

            Bundle b = getIntent().getExtras();
            // get id propinsi
            url = "https://kodepos-2d475.firebaseio.com/kota_kab/" + b.getString("idp") + ".json";
            
            ...

            // menampung data kota
            posList = new ArrayList<>();
            
            ...

            // filter berdasarkan nama kecamatan atau kelurahan
            final EditText filter = (EditText) findViewById(R.id.filter);
            filter.addTextChangedListener(new TextWatcher() {

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    String title = filter.getText().toString().trim().toLowerCase();
                    if(!TextUtils.isEmpty(title)) {
                        // clear tmpList
                        tmpList = new ArrayList<>();
                        for (int i = 0; i < posList.size(); i++) {
                            String kecamatan = posList.get(i).get("kecamatan").toLowerCase();
                            String kelurahan = posList.get(i).get("kelurahan").toLowerCase();
                            if (kecamatan.contains(title) || kelurahan.contains(title))  {
                                tmpList.add(posList.get(i));
                            }
                        }
                        // menampilkan hasil filter
                        ListAdapter adapter = new SimpleAdapter(
                                KotaActivity.this, tmpList,
                                R.layout.list_pos, new String[]{"kecamatan", "kelurahan", "kodepos"}, new int[]{R.id.kecamatan, R.id.kelurahan, R.id.kodepos});

                        lv.setAdapter(adapter);
                    } else {
                        // menampilkan original data
                        ListAdapter adapter = new SimpleAdapter(
                                KotaActivity.this, posList,
                                R.layout.list_pos, new String[]{"kecamatan", "kelurahan", "kodepos"}, new int[]{R.id.kecamatan, R.id.kelurahan, R.id.kodepos});

                        lv.setAdapter(adapter);
                    }

                }

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void afterTextChanged(Editable s) {
                    // TODO Auto-generated method stub

                }
            });
        }

        // Async task class to get json by making HTTP call
        private class GetPost extends AsyncTask<Void, Void, Void> {
        
            ...

            @Override
            protected Void doInBackground(Void... arg0) {
                HttpHandler sh = new HttpHandler();

                // Making a request to url and getting response
                String jsonStr = sh.makeServiceCall(url);

                Log.e(TAG, "Response from url: " + jsonStr);

                if (jsonStr != null) {
                    try {
                        JSONArray data = new JSONArray(jsonStr);

                        // Parser object array
                        for (int i = 0; i < data.length(); i++) {
                            JSONObject c = data.getJSONObject(i);

                            String kecamatan = c.getString("kecamatan");
                            String kelurahan = c.getString("kelurahan");
                            String kodepos = c.getString("kodepos");

                            HashMap<String, String> pos = new HashMap<>();

                            // adding each child node to HashMap key => value
                            pos.put("kecamatan", kecamatan);
                            pos.put("kelurahan", kelurahan);
                            pos.put("kodepos", kodepos);

                            // adding contact to contact list
                            posList.add(pos);
                        }
                    } catch (final JSONException e) {
                        
                        ...

                    }
                } else {
                    
                    ...

                }

                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
            
                ...

                // Updating parsed JSON data into ListView
                ListAdapter adapter = new SimpleAdapter(
                        KotaActivity.this, posList,
                        R.layout.list_pos, new String[]{"kecamatan", "kelurahan", "kodepos"}, new int[]{R.id.kecamatan, R.id.kelurahan, R.id.kodepos});

                lv.setAdapter(adapter);
            }

        }
        
        ...

    }

    bachors.com

  11. dan terakhir AndroidManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.bachors.kodepos">

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

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity
                android:name=".MainActivity"
                android:configChanges="orientation|keyboardHidden|screenSize">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity
                android:name=".PropinsiActivity"
                android:configChanges="orientation|keyboardHidden|screenSize" />
            <activity
                android:name=".KotaActivity"
                android:configChanges="orientation|keyboardHidden|screenSize" />
        </application>

    </manifest>

Atau sobat bisa mendownload source codenya disini. Selamat mencoba..

keyboard_arrow_up