• 4.09.2026 21:28:45
  • Admin Admin

Flutter mobil uygulama geliştirme projelerinde timeout, iptal, retry bütçesi ve idempotency anahtarlarını birlikte tasarlayın. Dio, Riverpod ve DevTools ile ağ hatalarını ölçülebilir istemci davranışlarına dönüştürün.

Flutter Mobil Uygulama Geliştirmede İstemci Ağ Dayanıklılığı

Flutter mobil uygulama geliştirmede ağ sözleşmesini timeout ile kurmak

Bir flutter eğitimi veya flutter kursu içinde HTTP isteğine yalnızca try-catch eklemek yeterli görünür; üretimde asıl karar, isteğin toplam ne kadar süre yaşayacağıdır. Dio'daki connectTimeout TCP bağlantısı için, receiveTimeout iki veri paketi arasındaki sessizlik için çalışır; hiçbiri tek başına uçtan uca deadline değildir. Örneğin ürün arama ekranı için 2.5 saniyelik toplam deadline, ödeme başlatma için 10 saniye deadline tanımlayın. Deadline dolduğunda soketi kapatmak, kullanıcı ekranı terk etmişken devam eden yanıtın state katmanına yazılmasını engeller ve radyo kullanımını azaltır.

final dio = Dio(BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: const Duration(milliseconds: 800), receiveTimeout: const Duration(milliseconds: 1500), sendTimeout: const Duration(milliseconds: 1500), headers: {'Accept': 'application/json'}, ));

Bu değerleri tüm endpoint'lere körlemesine uygulamayın. Endpoint envanterine deadlineMs, tekrar edilebilirlik ve kullanıcı etkisi alanlarını ekleyin. Örneğin 300 ms hedefli autocomplete çağrısında 800 ms bağlantı timeout'u zaten bütçeyi aşar; bağlantı, TLS ve sunucu sürelerini toplam deadline içinde bütçelendirmek gerekir. Sunucu tarafında da aynı deadline'ı X-Request-Deadline-Ms ile iletmek, istemci vazgeçtikten sonra pahalı veritabanı sorgusunun tamamlanmasını önler.

Dio ile iptal edilebilir istek ve gerçek toplam deadline uygulaması

Dio'nun timeout ayarlarını toplam deadline sanmak yaygın bir hatadır: yeniden yönlendirme, DNS çözümleme veya tekrar deneme döngüsü toplam beklemeyi uzatabilir. Her deneme için ayrı CancelToken üretip bir Timer ile iptal edin. Aynı CancelToken'ı paralel iki istekte paylaşmayın; bir widget dispose olduğunda yapılan iptal, ilgisiz isteği de keser.

Future<Response<T>> getWithinDeadline<T>( Dio dio, String path, {required Duration deadline, CancelToken? parentToken,}) async { final token = CancelToken(); final timer = Timer(deadline, () => token.cancel('total deadline exceeded')); parentToken?.whenCancel.then((_) => token.cancel('caller cancelled')); try { return await dio.get<T>(path, cancelToken: token); } on DioException catch (error) { if (token.isCancelled) { throw TimeoutException('GET $path exceeded $deadline', deadline); } rethrow; } finally { timer.cancel(); } }

Widget yaşam döngüsünde yalnızca mounted kontrolü yapmak ağ isteğini durdurmaz; sadece geç gelen sonucu görmezden gelir. İptal token'ını veri sağlayıcısının yaşam döngüsüne bağlayın. Bu ayrım özellikle flutter state management katmanında önemlidir: state sahibi dispose olduğunda hem kaynak tüketimi biter hem de eski yanıtın yeni ekrana yazılması engellenir.

Flutter state management içinde retry bütçesi ve idempotency

Retry sadece geçici hata sınıfları için uygulanmalıdır: 408, 429, 502, 503, 504 ve bağlantı kurulamadığı durumlar adaydır. 400, 401, 403, 404 veya JSON ayrıştırma hatasını tekrar etmek aynı hatalı isteği büyütür. GET, HEAD, PUT ve DELETE semantik olarak idempotent olabilir; POST için ise istemcinin ürettiği tek bir Idempotency-Key sunucu tarafından kalıcı olarak deduplicate edilmeden otomatik retry yapmayın. Anahtar her denemede değil, kullanıcı eylemi başına bir kez üretilmelidir.

Future<Response<T>> retryGet<T>(Dio dio, String path) async { const maxAttempts = 3; final random = Random(); for (var attempt = 1; attempt <= maxAttempts; attempt++) { try { return await getWithinDeadline<T>(dio, path, deadline: const Duration(seconds: 2)); } on DioException catch (e) { final code = e.response?.statusCode; final retryable = code == 408 || code == 429 || code == 502 || code == 503 || code == 504 || e.type == DioExceptionType.connectionError; if (!retryable || attempt == maxAttempts) rethrow; final capMs = min(800, 100 * (1 << (attempt - 1))); final jitterMs = random.nextInt(capMs + 1); await Future.delayed(Duration(milliseconds: jitterMs)); } } throw StateError('unreachable'); }

Riverpod kullanılıyorsa iptal token'ını provider'a ait tutun ve ref.onDispose ile kapatın. Böylece filtre değiştiğinde önceki arama sonuçları yeni filtre sonucunu ezemez. dart programlama eğitimi kapsamında sık görülen hata, AsyncValue.loading() durumunu her retry'da yeniden yayınlamaktır; ekranda gereksiz titreşim oluşur. İlk veriyi koruyup retry bilgisini ayrı bir alanla yayınlamak, stale veri ile kontrollü yenileme sağlar.

final productsProvider = AutoDisposeFutureProvider.family<List<Product>, String>((ref, query) async { final token = CancelToken(); ref.onDispose(() => token.cancel('search provider disposed')); final response = await getWithinDeadline<List<dynamic>>( dio, '/products', deadline: const Duration(milliseconds: 1800), parentToken: token, ); return response.data!.map(Product.fromJson).toList(); });

Cross platform mobil uygulama geliştirme için ağ farklarını test etmek

Cross platform mobil uygulama geliştirme sürecinde Android emülatörde çalışan akışın iOS cihazdaki ağ geçişiyle aynı davranacağını varsaymayın. Wi-Fi'dan hücresel ağa geçiş, arka plana alma ve captive portal senaryolarında bağlantı hata tipleri platform ve işletim sistemi tarafından farklı raporlanabilir. Uygulamanın kararını hata mesajına değil, kendi timeout ve retry politikasına dayandırın; hata mesajını yalnızca tanı verisi olarak kaydedin.

Kontrollü hata üretmek için geliştirme ortamında Toxiproxy kullanın. Proxy üzerinden 1200 ms gecikme ve bağlantı kesilmesi ekleyerek deadline'ın gerçekten çalıştığını doğrulayabilirsiniz:

toxiproxy-cli create api -l 0.0.0.0:8666 -u api.example.com:443
toxiproxy-cli toxic add api -t latency -a latency=1200 -a jitter=200
toxiproxy-cli toxic add api -t reset_peer -a timeout=3000
Test ortamında baseUrl değerini bu proxy'ye yönlendirin. TLS trafiğini proxy ile sonlandırıyorsanız test sertifikasını açıkça yükleyin; sertifika doğrulamasını kapatan badCertificateCallback = (_, __, ___) => true kodu test dalı dışında asla kalmamalıdır.

Bir diğer edge case, 429 yanıtıdır. Sunucu Retry-After gönderiyorsa istemcinin sabit backoff hesabı yerine bu değeri üst sınır ve toplam deadline ile birlikte değerlendirmesi gerekir. Kullanıcı arama ekranında 20 saniye sonra retry etmek anlamsızdır; isteği başarısız sayın ve kullanıcının yeni eylemini bekleyin. Arka plan senkronizasyonunda ise işletim sistemi planlayıcısına bırakmak daha doğru bir teslimat modeli olabilir.

DevTools ile önce-sonra ağ gecikmesi ve retry maliyeti ölçümü

Ağ dayanıklılığı değişikliğini performans iyileştirmesi diye kabul etmeden önce ölçün. Her istek için endpoint etiketi, deneme sayısı, toplam süre, HTTP kodu, iptal nedeni ve payload boyutunu kaydedin. dart:developer içindeki TimelineTask ile Flutter DevTools Performance görünümünde istemci tarafındaki süreyi frame olaylarıyla aynı zaman çizelgesinde inceleyebilirsiniz. Bu, örneğin 429 sonrası ana isolate üzerinde yapılan yanlışlıkla bloklayan dönüşümün scroll jank ile ilişkisini gösterir.

Future<T> traced<T>(String name, Future<T> Function() action) async { final task = TimelineTask(filterKey: 'network'); task.start(name, arguments: {'startedAt': DateTime.now().toIso8601String()}); final watch = Stopwatch()..start(); try { final value = await action(); task.finish(arguments: {'ok': true, 'elapsedMs': watch.elapsedMilliseconds}); return value; } catch (error) { task.finish(arguments: {'ok': false, 'elapsedMs': watch.elapsedMilliseconds, 'errorType': error.runtimeType.toString()}); rethrow; } }

Karşılaştırmayı aynı cihaz, aynı test veri kümesi ve aynı Toxiproxy profiliyle yapın. Önce mevcut istemcide 100 arama isteğinin p50, p95, timeout oranı ve istek başına ortalama deneme sayısını çıkarın. Sonra 1.8 saniye deadline, maksimum 3 deneme ve full-jitter değişikliğiyle aynı testi tekrarlayın. Başarı oranı yükselirken p95 yükseliyorsa retry bütçesi kullanıcı etkileşimi için fazla geniştir. Bu ölçüm yaklaşımı, flutter mobil uygulama geliştirme ekiplerinde policy değerlerini tahmin yerine veriyle belirler.

İlgili Eğitim

Flutter Eğitimi

Sık Sorulan Sorular

Flutter state management içinde ekran kapanınca Dio isteği nasıl iptal edilir?

İstek için bir CancelToken oluşturun, token'ı provider veya controller yaşam döngüsünde saklayın ve Riverpod'da ref.onDispose(() => token.cancel()) çağırın. Yalnız mounted kontrolü yanıtı yok sayar; soketi ve bekleyen Future'ı iptal etmez.

Flutter mobil uygulama geliştirmede Dio timeout neden toplam süreyi sınırlamaz?

connectTimeout bağlantı kurulmasını, receiveTimeout veri paketleri arasındaki beklemeyi denetler. DNS, yönlendirme, uygulama mantığı ve retry döngüsünün toplamı bu değerleri aşabilir. Uçtan uca sınır için Timer ile CancelToken iptali veya üst katmanda Future timeout kullanın.

Flutter kursu projelerinde POST isteğine otomatik retry eklemek güvenli mi?

Hayır. Ağ kopunca sunucunun POST'u işleyip işlemediği bilinmeyebilir ve ikinci deneme çift sipariş veya çift ödeme oluşturabilir. Sunucu Idempotency-Key değerini sonuçla birlikte saklıyor ve aynı anahtar için önceki sonucu dönüyorsa, aynı anahtarla sınırlı retry uygulanabilir.

Cross platform mobil uygulama geliştirme ağ testinde hangi araçla gecikme eklenir?

Toxiproxy ile endpoint önüne yerel bir proxy koyup latency, bandwidth ve reset_peer toxic'leri ekleyin. Flutter DevTools Performance görünümünde TimelineTask kayıtlarını açarak deadline, retry ve frame zamanlarının ilişkisini ölçün.

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