Service / Background Task pada Flutter
Implementasi service di Flutter dapat dilakukan melalui beberapa cara. Di antaranya adalah dengan menambahkan package/library, misalnya menggunakan package flutter_background_service https://pub.dev/packages/flutter_background_service/example
atau menggunakan package get_it https://pub.dev/packages/get_it,
contoh penggunaan library get_it ini dapat dibaca pada https://medium.com/flutter-community/creating-services-to-do-the-work-in-your-flutter-app-93d6c4aa7697.
Pada tutorial ini akan dibahas implementasi background task di Flutter melalui mekanisme isolate. Isolate adalah model Dart untuk membuat progran multithread, code yang dijalankan melalui isolate tidak berbagi memory dengan program utama.
Cara paling sederhana untuk mengimplementasikan isolate dalam program Dart adalah dengan menggunakan fungsi compute, pada tutorial berikut ini akan diuraikan contoh programnya.
Intro
Secara default, aplikasi yang dibangun menggunakan bahasa Dart bekerja pada single thread. Pada sebagian besar kasus, model single thread cara codingnya sederhana dan program dapat dijalankan dengan cepat tanpa mengalami penurunan kinerja aplikasi atau adanya tampilan UI yang tersendat-sendat (sering disebut sebagai "jank").
Namun pada kasus tertentu, sebuah aplikasi mungkin membutuhkan adanya komputasi yang cukup berat, misalnya melakukan parsing sebuah dokumen dalam format JSON yang berukuran besar. Jika operasi ini dilakukan lebih dari 16 milidetik, pengguna aplikasi akan mengalami jank.
Untuk mencegah terjadinya jank, developer aplikasi perlu memindahkan komputasi yang berat tersebut ke background. Pada Android, hal ini artinya menjadwalkan pekerjaan pada thread yang terpisah. Pada Flutter ini akan diimplementasikan menggunakan isolate.
Apa yang akan dibuat?
Pada tutorial ini akan dibuat sebuah program yang memproses data dalam bentuk json. File json yang diproses berukuran 1,1 MB dan berisi data 5.000 foto. Setiap record data berisi id foto, id album, dan url fotonya.
Penerapan isolate pada tutorial ini akan dilakukan melalui langkah-langkah berikut :
1. Buat project Flutter di VS Code
2. Tambahkan package http
Tambahkan packe dengan mengeksekusi perintah melalui command line
flutter pub add http
3. Buat class Photo
Class ini dibuat untuk memudahkan proses parsing data JSON menjadi object Photo.
class Photo { final int albumId; final int id; final String title; final String url; final String thumbnailUrl; const Photo({ required this.albumId, required this.id, required this.title, required this.url, required this.thumbnailUrl, }); factory Photo.fromJson(Map<String, dynamic> json) { return Photo( albumId: json['albumId'] as int, id: json['id'] as int, title: json['title'] as String, url: json['url'] as String, thumbnailUrl: json['thumbnailUrl'] as String, ); } }4. Buat method parsePhotos untuk mengubah response dari data JSON yang didapat ke bentuk List<Photo>;
// A function that converts a response body into a List<Photo>. List<Photo> parsePhotos(String responseBody) { final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>(); return parsed.map<Photo>((json) => Photo.fromJson(json)).toList(); }
Future<List<Photo>> fetchPhotos(http.Client client) async { final response = await client .get(Uri.parse('https://jsonplaceholder.typicode.com/photos')); // (a) melakukan request dan mendapatkan response berupa data json // Use the compute function to run parsePhotos in a separate isolate. return compute(parsePhotos, response.body); // (b) melakukan parsing data di background }
import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; Future<List<Photo>> fetchPhotos(http.Client client) async { final response = await client .get(Uri.parse('https://jsonplaceholder.typicode.com/photos')); // Use the compute function to run parsePhotos in a separate isolate. return compute(parsePhotos, response.body); } // A function that converts a response body into a List<Photo>. List<Photo> parsePhotos(String responseBody) { final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>(); return parsed.map<Photo>((json) => Photo.fromJson(json)).toList(); } class Photo { final int albumId; final int id; final String title; final String url; final String thumbnailUrl; const Photo({ required this.albumId, required this.id, required this.title, required this.url, required this.thumbnailUrl, }); factory Photo.fromJson(Map<String, dynamic> json) { return Photo( albumId: json['albumId'] as int, id: json['id'] as int, title: json['title'] as String, url: json['url'] as String, thumbnailUrl: json['thumbnailUrl'] as String, ); } } void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { const appTitle = 'Isolate Demo'; return const MaterialApp( title: appTitle, home: MyHomePage(title: appTitle), ); } } class MyHomePage extends StatelessWidget { const MyHomePage({super.key, required this.title}); final String title; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title), ), body: FutureBuilder<List<Photo>>( future: fetchPhotos(http.Client()), builder: (context, snapshot) { if (snapshot.hasError) { return const Center( child: Text('An error has occurred!'), ); } else if (snapshot.hasData) { return PhotosList(photos: snapshot.data!); } else { return const Center( child: CircularProgressIndicator(), ); } }, ), ); } } class PhotosList extends StatelessWidget { const PhotosList({super.key, required this.photos}); final List<Photo> photos; @override Widget build(BuildContext context) { return GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), itemCount: photos.length, itemBuilder: (context, index) { return Image.network(photos[index].thumbnailUrl); }, ); } }
Comments
Post a Comment