✦ Selamat Idul Fitri 1447 H 🌙 Taqabbalallahu minna wa minkum. Mohon maaf lahir dan batin. ✦
ALFAkwt

Mengelola Background Task di Flutter: WorkManager, Isolate, dan flutter_background_service

· 0 komentar · ± 5 menit baca · 👁 8 dilihat

Tidak semua pekerjaan aplikasi perlu — atau sebaiknya — dilakukan saat pengguna sedang aktif melihat layar. Sinkronisasi data, backup otomatis, pengiriman laporan terjadwal, pembersihan cache — ini semua adalah pekerjaan yang idealnya terjadi di latar belakang tanpa mengganggu pengalaman pengguna.

Tapi background execution di Android adalah topik yang lebih kompleks dari yang terlihat. Android secara agresif membatasi apa yang bisa dilakukan aplikasi di background — alasan baterainya bagus, tapi tidak selalu intuitif bagi developer.

Artikel ini membahas tiga pendekatan untuk background task di Flutter, dengan penjelasan kapan masing-masing tepat digunakan.


Memahami Batasan Background Android

Sebelum memilih solusi, penting untuk memahami apa yang Android izinkan dan larang untuk background execution:

Android Doze Mode (API 23+): Ketika perangkat idle dan tidak dicharging, Android menunda operasi jaringan, alarm, dan sinkronisasi secara berkala untuk menghemat baterai. Aplikasi di background mendapatkan "maintenance window" yang semakin jarang semakin lama perangkat idle.

Background Process Limits (API 26+): Aplikasi di background tidak bisa lagi memulai background service sembarangan. Background service yang tidak memiliki komponen foreground aktif bisa dibunuh oleh sistem kapan saja.

App Standby Buckets (API 28+): Android mengkategorikan aplikasi ke dalam bucket berdasarkan seberapa sering digunakan, dan membatasi frekuensi background task berdasarkan bucket tersebut.

Ini berarti tidak ada solusi background yang 100% reliable di semua kondisi — ada selalu kemungkinan sistem menunda atau membatalkan task. Desain yang baik harus mengantisipasi ini.


Pendekatan 1: WorkManager untuk Task Terjadwal

WorkManager adalah library Android Jetpack yang menangani background task yang perlu dijamin eksekusinya — bahkan jika aplikasi ditutup atau perangkat di-restart. Ia bekerja dengan menjadwalkan pekerjaan yang akan dieksekusi oleh sistem pada waktu yang tepat, menghormati batasan baterai Android.

Package Flutter untuk WorkManager: workmanager

// Di main.dart — inisialisasi
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Workmanager().initialize(
callbackDispatcher,
isInDebugMode: kDebugMode,
);
runApp(const MyApp());
}
// HARUS top-level function — akan dipanggil oleh sistem di isolate terpisah
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((taskName, inputData) async {
switch (taskName) {
case 'sinkronisasi-harian':
await _sinkronisasiData();
break;
case 'backup-cache':
await _backupCache();
break;
}
return true; // true = sukses, false = retry
});
}
// Daftarkan task periodik
await Workmanager().registerPeriodicTask(
'sinkronisasi-harian-id',
'sinkronisasi-harian',
frequency: const Duration(hours: 24),
constraints: Constraints(
networkType: NetworkType.connected,
requiresBatteryNotLow: true,
),
initialDelay: const Duration(minutes: 30),
);

WorkManager secara otomatis menangani retry jika task gagal, menghormati batasan Doze Mode, dan memastikan task dieksekusi meskipun aplikasi di-restart. Ini adalah pilihan terbaik untuk task periodik yang tidak butuh presisi waktu tinggi (WorkManager bisa menunda task beberapa menit tergantung kondisi sistem).


Pendekatan 2: flutter_background_service untuk Service yang Berjalan Lama

WorkManager cocok untuk task singkat yang terjadwal. Tapi bagaimana jika Anda butuh sesuatu yang berjalan terus-menerus — seperti memantau lokasi, mendengarkan pesan masuk, atau streaming data sensor?

Untuk ini, Anda butuh Foreground Service — service yang berjalan di background dengan notifikasi persisten yang memberitahu pengguna bahwa aplikasi aktif. Package flutter_background_service menyederhanakan ini:

// Inisialisasi di main.dart
Future<void> initBackgroundService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
onStart: onServiceStart,
autoStart: true,
isForegroundMode: true,
notificationChannelId: 'monitoring-channel',
initialNotificationTitle: 'Monitoring Aktif',
initialNotificationContent: 'Memantau data...',
),
iosConfiguration: IosConfiguration(
autoStart: true,
onForeground: onServiceStart,
),
);
await service.startService();
}
// Entry point service — top-level function
@pragma('vm:entry-point')
void onServiceStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
// Perbarui notifikasi secara periodik
Timer.periodic(const Duration(seconds: 30), (timer) async {
if (service is AndroidServiceInstance) {
if (await service.isForegroundService()) {
service.setForegroundNotificationInfo(
title: 'Monitoring Aktif',
content: 'Terakhir diperbarui: ${DateTime.now().formatWaktu}',
);
}
}
// Lakukan pekerjaan background di sini
final data = await _ambilDataSensor();
service.invoke('update', data.toMap());
});
// Dengarkan perintah dari UI
service.on('stop').listen((event) {
service.stopSelf();
});
}
// Di UI — kirim dan terima data dari service
FlutterBackgroundService().invoke('stop');
FlutterBackgroundService().on('update').listen((data) {
// Update UI dengan data terbaru dari background
});

Pendekatan 3: Dart Isolate untuk Background di Dalam Proses

Untuk task yang berat secara komputasi tapi tidak perlu berjalan ketika aplikasi di-close, Dart Isolate adalah pilihan yang lebih sederhana dan lightweight:

// Untuk task satu kali yang lama
final hasil = await compute(prosesDataBesar, inputData);
// Untuk task yang perlu komunikasi dua arah
final receivePort = ReceivePort();
final isolate = await Isolate.spawn(backgroundTask, receivePort.sendPort);
receivePort.listen((message) {
if (message is Map && message['tipe'] == 'progress') {
setState(() => _progress = message['nilai']);
} else if (message is Map && message['tipe'] == 'selesai') {
setState(() => _hasil = message['data']);
isolate.kill();
}
});

Isolate tidak bisa berjalan ketika aplikasi di-background (berbeda dengan WorkManager dan ForegroundService). Gunakan ini untuk operasi berat yang terjadi saat pengguna masih menggunakan aplikasi.


Perbandingan Praktis

Berikut rangkuman kapan menggunakan masing-masing:

WorkManager: Task periodik terjadwal (sync data setiap 24 jam, kirim laporan mingguan, cleanup cache). Bisa berjalan ketika aplikasi tertutup. Tidak perlu presisi waktu tinggi. Bisa di-retry otomatis jika gagal.

flutter_background_service: Service yang butuh berjalan terus-menerus ketika aplikasi di-background (tracking lokasi, monitoring sensor, streaming). Membutuhkan notifikasi foreground yang tidak bisa disembunyikan. Lebih boros baterai dari WorkManager.

Dart Isolate: Komputasi berat yang terjadi saat aplikasi aktif di foreground (parsing file besar, enkripsi, kompresi gambar). Paling sederhana diimplementasikan. Tidak bisa berjalan ketika aplikasi di-background.


Testing Background Task

Testing background task memiliki tantangan tersendiri karena behavior sistem yang sulit dikontrol. Beberapa strategi:

Untuk WorkManager: Gunakan WorkManager.getInstance().enqueue() dengan ExistingWorkPolicy.REPLACE dan pantau hasilnya via WorkInfo di log. Di debug mode, WorkManager menjalankan task lebih agresif dari kondisi production.

Untuk Background Service: Test logika bisnis di dalam service secara terpisah dari mekanisme background itu sendiri. Pisahkan kode yang melakukan pekerjaan sebenarnya dari kode yang mengelola lifecycle service.

Untuk semua: Log setiap eksekusi dengan timestamp ke persistent storage (SharedPreferences atau Hive), sehingga Anda bisa memverifikasi apakah task benar-benar berjalan sesuai jadwal dalam kondisi production.


Kesimpulan

Background execution di Android adalah domain yang membutuhkan pemahaman tentang constraint sistem, bukan hanya kode yang ditulis. Pilihan solusi yang tepat bergantung pada apakah task perlu berjalan saat aplikasi tertutup, seberapa sering berjalan, dan seberapa penting presisi waktu eksekusinya.

Mulai dari yang paling sederhana sesuai kebutuhan. WorkManager untuk task periodik sederhana. flutter_background_service hanya jika benar-benar butuh service yang persisten. Dan selalu rancang dengan asumsi task bisa tertunda atau dibatalkan oleh sistem — karena di Android, itu selalu kemungkinan yang nyata.


Komentar

Belum ada komentar. Jadilah yang pertama menulis.

Tulis Komentar