This article shows how to gain real performance improvements for large images and network images in Flutter using background isolates, TransferableTypedData, and ui.decodeImageFromList. It includes practical examples applicable in Flutter and Dart training contexts.
Flutter: Background Isolate ile Image Decode ve Zero-copy Cache Optimizasyonu
Neden arka plan decode - flutter mobil uygulama geliştirme için teknik gerekce
Teknik gerekce: büyük JPEG/PNG decode islemleri Dart ana izinde (UI thread) yapildiginda Dart heap churn artar, GC duraklamalari gelir ve frame bütçesini asarak jank olusur. Bunu olusturan mekanizma: image decode CPU-bound islemdir ve Dart tarafinda tamponlar olusturup siliyor - bu da GC pressure yaratir. Somut araç: profil icin 'flutter run --profile' ile uygulamayi calistirin ve DevTools Timeline'da 'Dart' ve 'Raster' parcaciklarina bakin. Ornek komut: "flutter run --profile --trace-skia" ile Skia trace ureterek GPU upload gecikmelerini de inceleyebilirsiniz.
Zero-copy TransferableTypedData ve Isolate.spawn ile arka plan decode ornegi
Bu bolumde TransferableTypedData kullanarak zero-copy seklinde byte'lari bir isolate'a gonderip isleyip geri almak uzerine somut bir ornek var. Paketler/araçlar: dart:ffi degil, dart:isolate, TransferableTypedData, DevTools CPU Profiler. Aşağıdaki kod anahtar kavramlari gosterir: ReceivePort, SendPort, TransferableTypedData.fromList, materialize ve Isolate.spawn.
import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
// Main isolate
Future decodeInBackground(Uint8List data) async {
final rp = ReceivePort();
await Isolate.spawn(_decodeEntry, rp.sendPort);
final sendPort = await rp.first as SendPort;
final response = ReceivePort();
// TransferableTypedData ile zero-copy transfer
sendPort.send([TransferableTypedData.fromList([data]), response.sendPort]);
final msg = await response.first as TransferableTypedData;
return msg.materialize().asUint8List();
}
// Background isolate entry
void _decodeEntry(SendPort initialReply) async {
final port = ReceivePort();
initialReply.send(port.sendPort);
await for (final message in port) {
final TransferableTypedData ttd = message[0] as TransferableTypedData;
final SendPort reply = message[1] as SendPort;
final Uint8List bytes = ttd.materialize().asUint8List();
// Örnek: burada native kütüphane kullanmak veya paket ile decode yapabilirsiniz
// Bu ornekte basitçe ayni veriyi geri gonderiyoruz (simulasyon)
reply.send(TransferableTypedData.fromList([bytes]));
}
}
Neden bu sekilde: TransferableTypedData, platformlar arasi kopyalanmayi minimize eder; Isolate.spawn ile decode isini ana izinden ayirirsiniz. Olcum icin once 'flutter run --profile' ile baseline alin, sonra bu degisikligi uygulayip tekrar cagirarak DevTools CPU profiler ve Timeline'da 'Dart' islemlerinin azalip azalmedigini kontrol edin.
ui.decodeImageFromList ile native decode ve RawImage kullanimi
Dart tarafinda bazi decode islemleri yerine engine'in native bitmap decode mekanizmasini kullanmak genellikle heap churn'i azaltir; bunun icin dart:ui'daki ui.decodeImageFromList fonksiyonunu kullanabilirsiniz. Bu yontem, decode edilen sonucu ui.Image olarak dondurur; bu sayede tekrar tekrar ImageProvider tarafindan decode edilmesini onlersiniz. Somut kod ornegi asagida:
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/widgets.dart';
Future decodeToUiImage(Uint8List bytes) async {
final Completer comp = Completer();
ui.decodeImageFromList(bytes, (ui.Image img) {
comp.complete(img);
});
return comp.future;
}
// Kullanimi: FutureBuilder ile RawImage gosterme
Widget buildImage(Uint8List bytes) {
return FutureBuilder(
future: decodeToUiImage(bytes),
builder: (c, s) {
if (s.connectionState != ConnectionState.done) return SizedBox();
return RawImage(image: s.data);
},
);
}
Dikkat edilmesi gerekenler: ui.Image nesnesini kullanmadiktan sonra 'dispose' etmelisiniz (örnegin kendi cache'inizde referanslar bittiginde s.data.dispose()). Bu yaklasim, 'cached_network_image' veya 'flutter_cache_manager' ile birlikte diske cekilmis orijinal bytes ile kombin edilirse agdan gelen buyuk resimler icin en az heap churn ile calisir.
Profiling ve olcum metodolojisi: DevTools, trace-skia ve karsilastirma
Olcum icin somut adimlar: 1) Baseline cek: "flutter run --profile --trace-skia" ile uygulamayi calistirin, 2) DevTools'u acin (tarayici: http://127.0.0.1:9100 veya 'flutter pub global run devtools' ile), 3) Timeline'da 'Frame' ve 'Raster' olaylarini kaydedin, 4) CPU Profiler ile Dart islemlerini kaydedin. Bu araclar: Flutter DevTools Timeline, CPU Profiler, Android systrace ("adb shell perfetto" veya "adb shell atrace"), iOS Instruments.
Olcum ornegi mantigi: baseline'da tek bir ekran kaydinda 'Dart' islemlerinin toplam suresi 60ms ve 'Raster' 40ms ise ve uyguladiğiniz background decode ile 'Dart' 30ms 'Raster' 18ms oluyorsa, mutlak azalma 30ms ve 22ms; yüzde olarak ~50% ve ~55% iyilesme verir. Mutlaka ayni senaryoda (ayni cihaz, ayni resimler, ayni ag kosullari) tekrarla ve ortalamayi alin.
Somut komutlar ve kayit alma:
- flutter run --profile --trace-skia
- DevTools ac: chrome'da open observatory URL veya 'flutter attach' ile baglan
- DevTools Timeline'da record yapip ayni user senaryosunu (sayfayi scroll etme, resimleri yukleme) calistirin
- Kayitlari export ederek before.json ve after.json olarak saklayin ve event duration'larini karsilastirin
Memory, OOM ve edge case'ler: TransferableTypedData sinirlari ve platform uyumlulugu
Edge case 1 - OOM: Cok buyuk dosyalar (eg. 100+ MB) transfer ederken Android'de dalgalanan bellek ve native heap problemleri gorebilirsiniz. Cozum: istemezseniz tam dosyayi isolate'a gondermeyin; server tarafinda on-the-fly resize yapin veya HTTP range ile parcali indirme yapin. Somut arac: backend tarafinda libvips veya libjpeg-turbo ile resize uygulayip daha kucuk bir payload gonderin.
Edge case 2 - TransferableTypedData sinirlari: TransferableTypedData platformlar arasinda farkli davranisabilir; test edin. Alternatif: platform-kanal (MethodChannel) ile native tarafda decode yaptirip sadece ui.Image ya da texture handle dondurmek. Paket onerisi: 'flutter_texture' veya 'texture' api'lerini kullanmak/icerdigini ozellestirmek. Somut kod/komut: Android tarafinda native decode icin JNI wrapper yazmak isterseniz, Android Studio ile 'flutter build apk --release' ve profili dogrulayin.
Best practice'ler:
- Her zaman ölçün: DevTools ile before/after > ortalama frame süresi
- ui.Image kullanıyorsanız manuel dispose:
myImage.dispose() - Disk cache icin 'flutter_cache_manager' kullanın:
CachedNetworkImage(imageUrl: url, cacheManager: CustomCacheManager()) - Isolate sayısını cihaza gore sınırlayın: isolate başına 1-2 CPU core'u hedefleyin
Uygulama notlari: integration ile flutter state management ve cache senkronizasyonu
Bu optimizasyonu state management ile entegre ederken dikkat: Rebuild fırtınasini onlemek icin Provider/Bloc/riverpod gibi state management cozumlerinde sadece byte listeleri veya ui.Image referanslarini degistirin; tum widget tree'yi degistirmeyin. Somut ornek: Riverpod ile imageProvider'i bir StateNotifier'da tutun ve bildirimleri sadece ilgili Image widget'a sinirlayin.
// Riverpod ornegi: sadece ilgili provider'i notify eder
final imageProvider = StateNotifierProvider(
(ref) => ImageNotifier(),
);
class ImageNotifier extends StateNotifier {
ImageNotifier(): super(null);
void setImage(ui.Image img) {
state = img; // sadece abone olan widget yeniden cizilir
}
}
Ayrica cross platform mobil uygulama geliştirme gereksiniminde her iki platformda da memory profiling yapin: Android Profiler ve iOS Instruments ile native heap ve Java/Kotlin/ObjC tarafli bellek kullanımini karsilastirin. Bu sekilde dart heap azalsa bile native tarafin etkilenip etkilenmedigini gorebilirsiniz.
Related Course
Frequently Asked Questions
flutter eğitimi sırasında arka plan isolate ile image decode nasil ogretilir?
Pratik olarak: 1) Basit TransferableTypedData ornegi yazin, 2) Isolate.spawn ile veri gonderip donus alin, 3) DevTools ile CPU profil kaydedip baseline ile karsilastirin. Somut komut: "flutter run --profile --trace-skia" ve DevTools Timeline kullanin. Kod ornegi icin makaledeki TransferableTypedData blokunu uygulayin.
dart programlama eğitimi icin TransferableTypedData ve Isolate.spawn arasindaki fark nedir?
TransferableTypedData byte dizilerini zero-copy olarak tasiyabilir; standart Isolate mesajlasmasi kopyalama yapar. Eger buyuk Uint8List'leri kopyalamak istemiyorsaniz TransferableTypedData.fromList kullanin. Somut ornek: Makaledeki Isolate.spawn/_decodeEntry orneginde TransferableTypedData kullanimi gosterilmektedir.
flutter kursu icinde native decode kullanimi ui.decodeImageFromList ile nasil ogretilmeli?
Ogrencilere once baseline decode ile Heap churn goreterek baslayin, sonra ui.decodeImageFromList ile native decode uygulayin ve DevTools Timeline'da farklari gosteren kayitlar alin. Somut kod: makaledeki decodeToUiImage fonksiyonunu kullanin ve RawImage ile gosterin; kullanimdan sonra ui.Image.dispose() yapmayi unutmayin.
flutter state management ile image cache entegrasyonu nasil yapilir?
State management tarafinda sadece ilgili provider/Notifier'i guncelleyerek tum agaci rebuild etmemek kilit. Somut araclar: Riverpod/Provider/Bloc; disk cache icin flutter_cache_manager; kod ornegi: makaledeki Riverpod ImageNotifier kullanimina bakin.
AI / LLM Discovery
Bu makale Opendart Akademi Flutter eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.



