• 29.10.2026 11:26:53
  • İbrahim Gökyar

Bu makale, flutter mobil uygulama geliştirme pratiklerinde büyük resimler ve ağdan gelen görüntüler için background isolate, TransferableTypedData ve ui.decodeImageFromList kullanarak nasıl gerçek performans kazanımı elde edeceğinizi gösterir. flutter eğitimi ve dart programlama eğitimi bağlamında uygulanabilir örnekler içerir.

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 işlemleri Dart ana izinde (UI thread) yapıldığında Dart heap churn artar, GC duraklamaları gelir ve frame bütçesini aşarak jank oluşur. Bunu oluşturan mekanizma: image decode CPU-bound işlemdir ve Dart tarafında tamponlar oluşturup siliyor - bu da GC pressure yaratır. Somut araç: profil için 'flutter run --profile' ile uygulamayı çalıştırın ve DevTools Timeline'da 'Dart' ve 'Raster' parçacıklarına bakin. Örnek komut: "flutter run --profile --trace-skia" ile Skia trace üreterek GPU upload gecikmelerini de inceleyebilirsiniz.

Zero-copy TransferableTypedData ve Isolate.spawn ile arka plan decode örneği

Bu bölümde TransferableTypedData kullanarak zero-copy şeklinde byte'ları bir isolate'a gönderip işleyip geri almak üzerine somut bir örnek var. Paketler/araçlar: dart:ffi değil, dart:isolate, TransferableTypedData, DevTools CPU Profiler. Aşağıdaki kod anahtar kavramları gösterir: 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 örnekte basitçe ayni veriyi geri gönderiyoruz (simulasyon)
    reply.send(TransferableTypedData.fromList([bytes]));
  }
}

Neden bu şekilde: TransferableTypedData, platformlar arası kopyalanmayi minimize eder; Isolate.spawn ile decode işini ana izinden ayırirsiniz. Ölçüm için önce 'flutter run --profile' ile baseline alın, sonra bu değişikliği uygulayıp tekrar çağırarak DevTools CPU profiler ve Timeline'da 'Dart' işlemlerinin azalip azalmedigini kontrol edin.

ui.decodeImageFromList ile native decode ve RawImage kullanimi

Dart tarafında bazı decode işlemleri yerine engine'in native bitmap decode mekanizmasini kullanmak genellikle heap churn'i azaltır; bunun için dart:ui'daki ui.decodeImageFromList fonksiyonunu kullanabilirsiniz. Bu yöntem, decode edilen sonucu ui.Image olarak döndürür; bu sayede tekrar tekrar ImageProvider tarafından decode edilmesini önlersiniz. Somut kod orneği aşagida:

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 kullanmadıktan sonra 'dispose' etmelisiniz (örnegin kendi cache'inizde referanslar bittiginde s.data.dispose()). Bu yaklasim, 'cached_network_image' veya 'flutter_cache_manager' ile birlikte diske çekilmiş orijinal bytes ile kombin edilirse ağdan gelen büyük resimler için en az heap churn ile calisir.

Profiling ve ölçüm metodolojisi: DevTools, trace-skia ve karsilastirma

Ölçüm için somut adımlar: 1) Baseline çek: "flutter run --profile --trace-skia" ile uygulamayı çalıştırın, 2) DevTools'u açın (tarayıcı: http://127.0.0.1:9100 veya 'flutter pub global run devtools' ile), 3) Timeline'da 'Frame' ve 'Raster' olaylarını kaydedin, 4) CPU Profiler ile Dart işlemlerini kaydedin. Bu araçlar: Flutter DevTools Timeline, CPU Profiler, Android systrace ("adb shell perfetto" veya "adb shell atrace"), iOS Instruments.

Ölçüm örnegi mantığı: baseline'da tek bir ekran kaydında 'Dart' işlemlerinin toplam süresi 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 ağ koşulları) tekrarla ve ortalamayi alin.

Somut komutlar ve kayıt alma:

  • flutter run --profile --trace-skia
  • DevTools ac: chrome'da open observatory URL veya 'flutter attach' ile bağlan
  • DevTools Timeline'da record yapip ayni user senaryosunu (sayfayi scroll etme, resimleri yukleme) çalıştırın
  • 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: Çok büyük dosyalar (eg. 100+ MB) transfer ederken Android'de dalgalanan bellek ve native heap problemleri görebilirsiniz. Çözüm: istemezseniz tam dosyayi isolate'a göndermeyin; server tarafında on-the-fly resize yapin veya HTTP range ile parçali indirme yapin. Somut araç: backend tarafında libvips veya libjpeg-turbo ile resize uygulayip daha küçük bir payload gönderin.

Edge case 2 - TransferableTypedData sinirlari: TransferableTypedData platformlar arasında farkli davranisabilir; test edin. Alternatif: platform-kanal (MethodChannel) ile native tarafda decode yaptirip sadece ui.Image ya da texture handle döndürmek. Paket onerisi: 'flutter_texture' veya 'texture' api'lerini kullanmak/içerdigini özelleştirmek. Somut kod/komut: Android tarafında native decode için JNI wrapper yazmak isterseniz, Android Studio ile 'flutter build apk --release' ve profili doğrulayin.

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 için '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ınasını önlemek için Provider/Bloc/riverpod gibi state management çözümlerinde sadece byte listeleri veya ui.Image referanslarini değiştirin; tum widget tree'yi değiştirmeyin. 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 kullanimini karsilastirin. Bu sekilde dart heap azalsa bile native tarafin etkilenip etkilenmedigini gorebilirsiniz.

İlgili Eğitim

Flutter Eğitimi

Sık Sorulan Sorular

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.

Opendart Akademi llms.txt

📚 Bu konuyu Opendart Akademi'de öğrenin: Flutter eğitimi · Flutter eğitimi hakkında · YouTube video dersleri · Abone ol