Tiga Pahlawan
Di
Belakang Layar 🦸♂️
Aplikasi yang bagus tidak mati ketika ditutup! Belajar membuat Service yang jalan di background, menangkap sinyal sistem dengan Broadcast Receiver, dan menyapa user lewat Notification!
1. Service (Pekerja Keras)
Kalau Activity itu seperti pelayan toko yang menjaga etalase (butuh layar/UI), maka Service adalah pekerja di gudang belakang yang tidak pernah kelihatan.
Service tidak memiliki UI (User Interface). Tugasnya menyelesaikan proses berdurasi lama. Walaupun kamu menekan tombol Home dan kembali ke layar awal HP, Service akan tetap bekerja!
Contoh Penggunaan Nyata:
- Memutar musik (Spotify/Joox).
- Mengunduh file besar di background.
- Melacak GPS rute lari/sepeda (Strava).
Background vs Foreground Service
Background Service
Kerja diam-diam. Sistem Android seringkali "membunuhnya" jika HP butuh RAM karena dianggap tidak penting.
Foreground Service
Service VIP. Wajib memunculkan Notifikasi permanen di layar HP agar user tahu. Susah dibunuh oleh sistem Android.
2. Broadcast Receiver (Sang Satpam)
Pernahkah aplikasimu tiba-tiba menampilkan pop-up "Koneksi Terputus!" saat WiFi HP dimatikan? Atau layar berkedip saat baterai sisa 15%? Siapa yang memberi tahu aplikasi tentang kejadian itu? Jawabannya: Broadcast Receiver.
Sistem Siaran (Broadcasting)
Sistem operasi Android secara terus-menerus berteriak (siaran radio) mengabarkan kejadian penting: "Baterai mau habis!", "HP selesai Booting!", "Mode Pesawat aktif!".
Menangkap Siaran (Receiver)
Aplikasi kita bisa
membuat class turunan BroadcastReceiver. Kita pasang 'antena' untuk
mendengarkan topik tertentu. Saat topik itu disiarkan Android, aplikasi kita akan
merespon!
3. Notification (Menyapa User)
Pemberitahuan (Push Notification) adalah cara aplikasi menyapa user yang sedang tidak membuka aplikasi tersebut. Ada sebuah aturan penting sejak Android versi 8.0 (Oreo) yang sering membuat bingung developer pemula:
Peringatan Keras: Notification Channel!
Sejak Android 8.0+, kamu WAJIB
membuat NotificationChannel sebelum memunculkan notifikasi. Channel ini
membiarkan user mengatur notifikasi mana yang berbunyi keras dan mana yang sunyi. Jika kamu
lupa membuat Channel, notifikasimu tidak akan pernah muncul!
Izin Android 13 (Tiramisu)
Untuk Android versi 13 ke atas, memunculkan
notifikasi kini dianggap berbahaya. Kamu harus menambahkan
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
di Manifest!
Kaitan Tiga Pilar dengan Activity Lifecycle
Pernah bertanya-tanya, apa hubungannya semua fitur background ini dengan siklus hidup Activity? Jawabannya: Sangat Erat! Mereka bertiga hidup dan mati berdasarkan fase Activity-mu.
Service: Sang Pemberontak
Biasanya dihidupkan lewat Intent dari tombol (di UI) atau saat Activity baru lahir.
Ajaib! Saat Activity
mati/di-kill, Service TETAP HIDUP berjalan di background sampai dia
memanggil stopSelf().
Receiver: Awas Bocor!
Waktu yang tepat untuk
mendaftarkan (pasang antena) registerReceiver agar siap
mendengarkan sinyal.
WAJIB DICABUT! Gunakan
unregisterReceiver. Jika kamu membiarkan antena terpasang saat
aplikasi mati, akan terjadi Memory Leak (Kebocoran RAM)!
Notification: Jembatan UI
Saat user pencet tombol Home, layar tertutup. Inilah saat yang tepat menembakkan Notifikasi "Aplikasi berjalan di latar...".
Saat notifikasi diklik, ia akan
memicu onRestart() atau onCreate(), membangunkan
kembali sang Activity ke panggung utama!
4. Mega Simulator
Coba mainkan ketiga fitur background ini! Aktifkan Service, simulasikan kejadian baterai HP yang melemah (Broadcast), dan tembakkan Notifikasi dari sistem!
Panel Kontrol Fitur
1. Background Service
MATIMeski layar kembali ke Home, musik/tugas tetap berjalan di latar belakang.
2. Broadcast Receiver
Memaksa Android menembakkan siaran radio (Intent) ke seluruh HP.
3. NotificationManager
Membangun notifikasi dan mengirimkannya ke Status Bar atas HP.
Halo, ini pesan dari NotificationManager! Coba klik aku.
My App
Music Service
Menunggu perintah...
Log Aplikasi (Receiver)
5. Bedah Kode Lengkap
Sesuai dengan Simulator di atas, ini adalah kode utuh yang siap dieksekusi di Android Studio. Perhatikan struktur pembuatan Notification Channel dan deklarasi Service di AndroidManifest!
AndroidManifest.xml
Wajib mendeklarasikan Izin Notifikasi (Android 13+) dan mendaftarkan kelas Service serta Receiver agar dikenali oleh sistem!
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.superapp">
<!-- Izin memunculkan Notifikasi (Wajib untuk Android 13 / Tiramisu ke atas) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.MyApp">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- DAFTARKAN SERVICE DI SINI -->
<service android:name=".MusicService" />
<!-- DAFTARKAN RECEIVER DI SINI (Contoh deteksi colokan charger) -->
<receiver android:name=".PowerReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
</application>
</manifest>
MainActivity.java (Pemanggil Notifikasi)
Menangani klik UI, membuat
NotificationChannel (wajib untuk Android 8.0+), dan mengirimkan
NotificationManager.
package com.example.superapp;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
public class MainActivity extends AppCompatActivity {
// ID unik untuk Channel dan Notifikasi
private static final String CHANNEL_ID = "INFO_CHANNEL";
private static final int NOTIF_ID = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnService = findViewById(R.id.btnService);
Button btnNotif = findViewById(R.id.btnNotif);
// 1. Aksi Tombol Mulai/Stop Service Musik
btnService.setOnClickListener(v -> {
Intent serviceIntent = new Intent(MainActivity.this, MusicService.class);
// Untuk stop, gunakan stopService(serviceIntent);
startService(serviceIntent);
});
// 2. Aksi Kirim Push Notification
btnNotif.setOnClickListener(v -> kirimNotifikasi());
}
private void kirimNotifikasi() {
NotificationManager notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// WAJIB: Buat Channel untuk Android 8.0 (Oreo) ke atas
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"Notifikasi Informasi",
NotificationManager.IMPORTANCE_HIGH // Agar muncul pop-up melayang di atas (Heads-up)
);
notifManager.createNotificationChannel(channel);
}
// PENDING INTENT: Aksi ketika notifikasi di-klik (Buka MainActivity lagi)
Intent intentBuka = new Intent(this, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(
this, 0, intentBuka, PendingIntent.FLAG_IMMUTABLE
);
// Bangun Notifikasinya (Wujud visualnya)
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification) // Wajib ada icon kecil (biasanya warna putih/transparan)
.setContentTitle("Pesan Baru Masuk!")
.setContentText("Halo, ini pesan dari NotificationManager. Coba klik!")
.setAutoCancel(true) // Otomatis hilang jika diklik
.setContentIntent(pIntent); // Masukkan aksi klik
// Tembakkan (Munculkan di layar)
notifManager.notify(NOTIF_ID, builder.build());
}
}
MusicService.java (Pekerja Background)
Class ini meng-extends
Service. Metode onStartCommand akan dieksekusi terus di
belakang layar meskipun user menekan tombol Home HP.
package com.example.superapp;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MusicService extends Service {
private MediaPlayer player;
@Override
public IBinder onBind(Intent intent) {
// Hanya dipakai jika butuh komunikasi bolak-balik dengan Activity (Bound Service)
return null;
}
// Dipanggil SATU KALI saat service baru diciptakan
@Override
public void onCreate() {
super.onCreate();
// Pastikan ada lagu_kopi.mp3 di res/raw
player = MediaPlayer.create(this, R.raw.lagu_kopi);
player.setLooping(true); // Putar terus-menerus
}
// Dipanggil setiap kali Activity menjalankan "startService(intent)"
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Music Service Dimulai di Latar Belakang!", Toast.LENGTH_SHORT).show();
player.start();
Log.d("SERVICE_LOG", "Service sedang bermain musik...");
// START_STICKY: Jika sistem OS mematikan service ini karena kurang RAM,
// OS akan berusaha menghidupkannya kembali otomatis setelah RAM lega.
return START_STICKY;
}
// Dipanggil ketika "stopService(intent)" dieksekusi
@Override
public void onDestroy() {
super.onDestroy();
player.stop();
player.release();
Toast.makeText(this, "Music Service Dihentikan!", Toast.LENGTH_SHORT).show();
}
}
PowerReceiver.java (Sang Pendengar)
Class ini meng-extends
BroadcastReceiver. Fungsi onReceive akan otomatis "terbangun"
ketika sistem OS Android menembakkan sinyal yang didaftarkan (seperti mendeteksi kabel
charger dicabut/dicolok).
package com.example.superapp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class PowerReceiver extends BroadcastReceiver {
// Fungsi ini akan dieksekusi HANYA KETIKA sinyal kejadian (Event) ditangkap!
@Override
public void onReceive(Context context, Intent intent) {
// Periksa sinyal kejadian (Action) apa yang baru saja disiarkan oleh OS Android?
String aksiSistem = intent.getAction();
if (aksiSistem == null) return;
if (aksiSistem.equals(Intent.ACTION_POWER_CONNECTED)) {
// HP Sedang di-cas!
Toast.makeText(context, "⚡ Daya Terhubung. Mengisi Baterai...", Toast.LENGTH_LONG).show();
} else if (aksiSistem.equals(Intent.ACTION_POWER_DISCONNECTED)) {
// Kabel charger dicabut!
Toast.makeText(context, "⚠️ Peringatan: Daya Terputus!", Toast.LENGTH_LONG).show();
}
}
}
6. Tugas Puncak: Alarm Palsu!
Pernah melihat pesan notifikasi WhatsApp "Sedang memeriksa pesan baru..." yang berjalan sendiri? Mari kita buat sistem serupa menggunakan gabungan Service dan Notification!
Misi Project Utama (Fake Sync App):
- Buat `MainActivity` dengan satu tombol bertuliskan "Mulai Sinkronisasi Data".
- Buat sebuah class `SyncService.java` (Turunan `Service`). Jangan lupa daftarkan di AndroidManifest!
- Ketika tombol diklik, jalankan `SyncService` tersebut menggunakan `startService()`.
- Di dalam `onStartCommand` milik Service, munculkan Toast: "Sinkronisasi dimulai di background...". Lalu, panggil NotificationManager untuk memunculkan notifikasi berjudul: "Data tersinkronisasi!".
- *(Tantangan Ekstra: Bisakah kamu menggunakan fungsi `Handler(Looper.getMainLooper()).postDelayed` di dalam Service agar notifikasinya baru muncul 5 detik setelah tombol diklik?)*
Tips Pro: Menunda Aksi di Android (Delay)
// Di dalam onStartCommand pada class SyncService.java
Toast.makeText(this, "Memproses data di background...", Toast.LENGTH_SHORT).show();
// Kita menggunakan Handler untuk MENUNDA eksekusi kode selama 5000ms (5 Detik)
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
// KODE DI DALAM SINI BARU AKAN JALAN SETELAH 5 DETIK!
// 1. Buat kode NotificationChannel di sini
// 2. Buat NotificationCompat.Builder di sini
// 3. Panggil notifManager.notify(...) di sini!
// Jangan lupa hentikan service-nya jika tugas sudah kelar agar tidak memakan RAM
stopSelf();
}
}, 5000); // 5000 ms = 5 detik