Spinner (Combo Box) di Android: Data Statis & dari JSON
Oleh Afa HernandesDiperbarui 6 menit baca
Seri · Bagian 3 dari 9Komponen UI Android
- 1Cara Membuat Project Baru di Android Studio
- 2Membuat Loading/Splash Screen di Android Studio
- 3Spinner (Combo Box) di Android: Data Statis & dari JSON
- 4Cara Menggunakan RadioButton di Android
- 5Cara Membuat Alert Dialog di Android Studio (Lengkap + Loading)
- 6Date Picker Dialog di Android
- 7Cara Load Gambar dari URL di Android
- 8Membuka URL & Aplikasi Lain dari Button Android (Uri.parse)
- 9Source Code Halaman Dashboard UI Android
Daftar isi
- Persiapan
- Langkah 1: Buat layout
- Langkah 2: Spinner dengan data statis
- Langkah 3: Ambil nilai yang dipilih
- Langkah 4: Pilih item otomatis berdasarkan nilai
- Langkah 5: Spinner dengan data JSON dari server
- Endpoint PHP
- Class model
- Mengambil data di background
- Izin internet
- Error yang sering muncul
- Pertanyaan yang sering diajukan
- Kesimpulan
Spinner adalah komponen drop-down di Android, yang di dunia web biasa disebut combo box atau <select>. Spinner cocok untuk pilihan yang jumlahnya terbatas, seperti agama, jenis kelamin, jurusan, atau kategori produk. Layar tetap ringkas, dan pengguna tidak perlu mengetik.
Di tutorial ini kita membuat dua spinner:
- Spinner dengan data statis dari
string-array, misalnya daftar agama - Spinner dengan data dari server dalam format JSON, misalnya daftar beasiswa dari database MySQL
Kita juga membahas cara mengambil nilai yang dipilih dan cara memilih item secara otomatis berdasarkan nilai tertentu. Ini sangat dibutuhkan untuk form edit data.
Persiapan
- Android Studio versi terbaru, project Empty Views Activity dengan bahasa Java
- Untuk bagian JSON: web server lokal seperti XAMPP dengan PHP dan MySQL
Langkah 1: Buat layout
Buka res/layout/activity_main.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" android:padding="24dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Agama" />
<Spinner android:id="@+id/spinAgama" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="48dp" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="Beasiswa" />
<Spinner android:id="@+id/spinBeasiswa" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="48dp" />
<TextView android:id="@+id/tvHasil" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:textStyle="bold" />
</LinearLayout>Langkah 2: Spinner dengan data statis
Untuk data tetap, simpan pilihan di file resource, bukan di dalam kode Java. Buat file res/values/arrays.xml:
<resources> <string-array name="agama"> <item>Islam</item> <item>Kristen</item> <item>Katolik</item> <item>Hindu</item> <item>Buddha</item> <item>Konghucu</item> </string-array></resources>Lalu hubungkan ke Spinner lewat ArrayAdapter di onCreate():
Spinner spinAgama = findViewById(R.id.spinAgama);
ArrayAdapter<CharSequence> adapterAgama = ArrayAdapter.createFromResource( this, R.array.agama, android.R.layout.simple_spinner_item);adapterAgama.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spinAgama.setAdapter(adapterAgama);Ada dua layout bawaan Android yang dipakai di sini: simple_spinner_item untuk tampilan saat Spinner tertutup, dan simple_spinner_dropdown_item untuk daftar saat Spinner dibuka.
Alternatif: jika datanya berasal dari array Java, gunakan
new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, arrayAnda). Cara pakai selanjutnya sama.
Langkah 3: Ambil nilai yang dipilih
Pasang OnItemSelectedListener untuk merespons setiap kali pengguna memilih item:
spinAgama.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { String dipilih = parent.getItemAtPosition(position).toString(); tvHasil.setText("Agama: " + dipilih); }
@Override public void onNothingSelected(AdapterView<?> parent) { }});Jika nilainya hanya dibutuhkan saat tombol Simpan ditekan, Anda tidak perlu listener. Cukup baca spinAgama.getSelectedItem().toString() saat menyimpan.
Langkah 4: Pilih item otomatis berdasarkan nilai
Di form edit data, Spinner harus langsung menampilkan nilai yang tersimpan, misalnya “Hindu”. Gunakan getPosition() dari adapter:
String agamaTersimpan = "Hindu"; // misalnya dari database atau JSONint posisi = adapterAgama.getPosition(agamaTersimpan);if (posisi >= 0) { spinAgama.setSelection(posisi);}getPosition() membedakan huruf besar dan kecil. Kalau data dari database bisa berbeda kapitalisasinya, samakan dulu formatnya, misalnya dengan menyimpan nilai persis seperti di arrays.xml.
Langkah 5: Spinner dengan data JSON dari server
Untuk data yang bisa berubah, seperti daftar beasiswa, ambil datanya dari server. Kita butuh tiga bagian: endpoint PHP yang mengirim JSON, class model, dan kode Android yang mengambil data di background thread.
Endpoint PHP
Contoh tabel beasiswa dengan kolom id_beasiswa dan nama_beasiswa. Simpan file berikut di htdocs/api/beasiswa_show.php:
<?phpheader('Content-Type: application/json');
$conn = new mysqli('localhost', 'root', '', 'db_kampus');if ($conn->connect_error) { echo json_encode(['sukses' => 0, 'pesan' => 'Koneksi database gagal']); exit;}
$result = $conn->query('SELECT id_beasiswa, nama_beasiswa FROM beasiswa ORDER BY nama_beasiswa');echo json_encode([ 'sukses' => 1, 'record' => $result->fetch_all(MYSQLI_ASSOC),]);Buka alamatnya di browser untuk memastikan hasilnya seperti ini:
{ "sukses": 1, "record": [ { "id_beasiswa": "B01", "nama_beasiswa": "Beasiswa Prestasi" }, { "id_beasiswa": "B02", "nama_beasiswa": "KIP Kuliah" } ]}Class model
Spinner sering perlu menampilkan nama tetapi menyimpan ID. Daripada memakai dua array terpisah, buat class kecil. Teks yang tampil di Spinner diambil dari toString():
public class Beasiswa { public final String id; public final String nama;
public Beasiswa(String id, String nama) { this.id = id; this.nama = nama; }
@Override public String toString() { return nama; // teks yang tampil di Spinner }}Mengambil data di background
Request jaringan tidak boleh dijalankan di thread utama. Versi lama tutorial ini memakai AsyncTask, yang sudah deprecated sejak Android 11. Penggantinya adalah ExecutorService untuk proses di background dan Handler untuk kembali ke thread utama. Keduanya sudah tersedia tanpa library tambahan.
// ganti dengan IP komputer Anda; dari emulator, localhost komputer = 10.0.2.2private static final String BASE_URL = "http://10.0.2.2/api/";
private final ExecutorService executor = Executors.newSingleThreadExecutor();private final Handler mainHandler = new Handler(Looper.getMainLooper());
private void muatBeasiswa() { executor.execute(() -> { List<Beasiswa> hasil = new ArrayList<>(); HttpURLConnection conn = null; try { conn = (HttpURLConnection) new URL(BASE_URL + "beasiswa_show.php").openConnection(); conn.setConnectTimeout(10000); conn.setReadTimeout(10000);
StringBuilder sb = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { String line; while ((line = reader.readLine()) != null) sb.append(line); }
JSONObject json = new JSONObject(sb.toString()); if (json.getInt("sukses") == 1) { JSONArray record = json.getJSONArray("record"); for (int i = 0; i < record.length(); i++) { JSONObject o = record.getJSONObject(i); hasil.add(new Beasiswa(o.getString("id_beasiswa"), o.getString("nama_beasiswa"))); } } } catch (Exception e) { Log.e("Spinner", "Gagal memuat beasiswa", e); } finally { if (conn != null) conn.disconnect(); } // kembali ke thread utama untuk mengubah tampilan mainHandler.post(() -> tampilkanBeasiswa(hasil)); });}
private void tampilkanBeasiswa(List<Beasiswa> data) { ArrayAdapter<Beasiswa> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, data); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinBeasiswa.setAdapter(adapter);}
@Overrideprotected void onDestroy() { super.onDestroy(); executor.shutdown();}Panggil muatBeasiswa() di onCreate(). Untuk mengambil ID dari item yang dipilih:
Beasiswa terpilih = (Beasiswa) spinBeasiswa.getSelectedItem();String idBeasiswa = terpilih.id; // simpan ID ini ke database, bukan namanyaIzin internet
Tambahkan izin berikut di AndroidManifest.xml, di luar tag <application>:
<uses-permission android:name="android.permission.INTERNET" />Karena contoh ini memakai http:// (bukan https://), Android 9 ke atas akan memblokir request-nya secara default. Ikuti langkah di artikel Mengatasi JSON/HTTP Tidak Jalan di Android 9+ untuk mengizinkannya saat pengembangan.
Error yang sering muncul
NetworkOnMainThreadException. Request jaringan dijalankan langsung di onCreate(). Pindahkan ke background thread seperti contoh executor.execute() di atas.
Spinner kosong padahal JSON muncul di browser. Periksa tiga hal: izin INTERNET sudah ada, alamat server benar (gunakan 10.0.2.2 di emulator, atau IP komputer Anda di HP sungguhan), dan request http:// sudah diizinkan. Lihat pesan error lengkapnya di tab Logcat dengan filter Spinner.
onItemSelected terpanggil sendiri saat aplikasi dibuka. Itu perilaku normal: Spinner selalu memilih item pertama saat adapter dipasang. Jika ini mengganggu, abaikan panggilan pertama dengan sebuah variabel penanda, atau baca nilainya hanya saat tombol Simpan ditekan.
ClassCastException saat getSelectedItem(). Tipe adapter tidak sesuai dengan yang di-cast. Spinner beasiswa memakai ArrayAdapter<Beasiswa>, jadi cast ke Beasiswa, bukan ke String.
Pertanyaan yang sering diajukan
Apakah ada pengganti Spinner yang lebih modern?
Untuk tampilan Material Design, banyak aplikasi memakai Exposed Dropdown Menu, yaitu AutoCompleteTextView di dalam TextInputLayout dari library Material Components. Tampilannya mirip kolom input dengan panah. Konsep adapter-nya sama dengan Spinner.
Bagaimana jika datanya ratusan item?
Spinner kurang nyaman untuk daftar panjang karena pengguna harus menggulir. Gunakan AutoCompleteTextView agar pengguna bisa mengetik untuk mencari.
Kesimpulan
Spinner diisi lewat ArrayAdapter: gunakan createFromResource() untuk data statis, dan list objek model untuk data dari server. Ambil nilai dengan getSelectedItem(), pilih nilai tersimpan dengan getPosition() + setSelection(), dan pastikan request jaringan berjalan di background thread.
Lanjutkan ke bagian berikutnya di seri Komponen UI Android: RadioButton.


