Flutter önbellekleme stratejileri: yerel önbellek, eski veri ve yenileme kuralları — ne saklanmalı, ne zaman geçersiz kılınmalı ve ekranlar nasıl tutarlı tutulmalı.

Bir mobil uygulamada önbellekleme, verinin bir kopyasını yakında (hafızada veya cihazda) tutmak ve bir sonraki ekranın anında render olmasını sağlamak demektir. Bu veri bir ürün listesi, kullanıcı profili veya arama sonuçları olabilir.
Zor olan kısmı şu: önbelleğe alınan veri sıklıkla biraz yanlış olur. Kullanıcılar bunu çabuk fark eder: güncellenmeyen bir fiyat, takılı kalmış görünen bir bildirim sayacı ya da editledikten hemen sonra eski bilgileri gösteren bir detay ekranı. İşin can sıkıcı yanı zamanlamadır. Aynı uç nokta pull-to-refresh sonrası doğru görünebilir, ama geri navigasyon, uygulama yeniden gelme veya hesap değiştirince yanlış olabilir.
Gerçek bir takas vardır. Her zaman taze veriyi çekerseniz ekranlar yavaş ve takılgan hisseder, pil ve veri boşa gider. Agresif önbellekleme yaparsanız uygulama hızlı hisseder ama kullanıcılar gördüklerine güvenmeyi bırakır.
Basit bir hedef yardımcı olur: tazeliği öngörülebilir kılın. Her ekranın hangi veriyi gösterebileceğine (taze, hafifçe eski, ya da çevrimdışı), verinin ne kadar süre yaşayacağına ve hangi olayların onu geçersiz kılacağına karar verin.
Ortaok çerçevesi: bir kullanıcı bir siparişi açar, sonra sipariş listesine geri döner. Liste önbellekten gelirse eski durumu gösterebilir. Her seferinde yenilerseniz liste titreyip yavaş hissedilebilir. "Önce önbelleği anında göster, arka planda yenile, yanıt gelince her iki ekranı da güncelle" gibi net kurallar gezinme boyunca deneyimi tutarlı yapar.
Önbellek sadece "kaydedilmiş veri" değildir. Bu, kaydedilmiş bir kopya artı o kopyanın ne zaman geçerli olduğuna dair bir kuraldır. Yükü sadece payload olarak saklayıp kuralı atlarsanız iki gerçeklik versiyonunuz olur: bir ekran yeni bilgiyi gösterir, diğeri dünün verisini.
Pratik bir model her önbelleğe alınmış öğeyi üç durumdan birine koymaktır:
Bu çerçeve UI'nizin her seferinde aynı şekilde tepki vermesini sağlar.
Tazelik kuralları takım arkadaşınıza açıklayabileceğiniz sinyallere dayanmalıdır. Yaygın seçimler zaman tabanlı sona erme (örneğin 5 dakika), sürüm değişikliği (şema veya uygulama sürümü), kullanıcı eylemi (pull to refresh, submit, delete) veya sunucu ipucu (ETag, last-updated zaman damgası veya açık bir "cache invalid" yanıtı) olabilir.
Örnek: bir profil ekranı önbelleğe alınmış kullanıcı verisini anında yükler. Eğer "eski ama kullanılabilir" ise önbellekteki isim ve avatarı gösterir, sonra sessizce yeniler. Kullanıcı profilini az önce düzenlediyse bu "yenilenmeli" anıdır. Uygulama önbelleği hemen güncellemeli ki her ekran tutarlı kalsın.
Bu kurallara kim karar verecek? Çoğu uygulamada en iyi varsayılan: veri katmanı tazelik ve geçersiz kılmadan sorumludur, UI sadece tepki verir (önbelleği göster, yükleme göster, hata göster) ve backend mümkünse ipuçları sağlar. Bu, her ekranın kendi kuralını icat etmesini engeller.
İyi önbellekleme bir soruyla başlar: bu veri biraz eski olsa kullanıcıya zarar verir mi? Cevap "muhtemelen sorun olmaz" ise genellikle yerel önbelleğe almak uygundur.
Sıklıkla okunan ve yavaş değişen veriler genellikle önbelleğe değer: kullanıcıların sık kaydırdığı feed ve listeler, katalog tarzı içerik (ürünler, makaleler, şablonlar) ve kategoriler veya ülkeler gibi referans verisi. Ayarlar ve tercihler ile isim ve avatar URL'si gibi temel profil bilgileri de buraya girer.
Riskli taraf ise para ile veya zamana duyarlı olan her şeydir. Bakiye, ödeme durumu, stok durumu, randevu slotları, teslimat ETA'ları ve "son görüldü" gibi bilgiler eskiyse gerçek sorunlara yol açabilir. Hız için önbelleğe alınabilirler ama karar noktalarında (örneğin siparişi onaylamadan hemen önce) önbelleği geçici bir placeholder olarak kabul edip yenileme zorunlu kılın.
Türetilmiş UI durumu ayrı bir kategoridir. Seçili sekme, filtreler, arama sorgusu, sıralama ya da kaydırma pozisyonunu kaydetmek gezinmeyi yumuşatır. Ancak eski seçimler beklenmedik şekilde geri gelince kafa karıştırabilir. Basit bir kural: kullanıcı aynı akışta kaldığı sürece UI durumunu hafızada tutun, ama kullanıcı kasıtlı olarak "yeniden başla" yaptığında (ana ekrana dönmek gibi) sıfırlayın.
Güvenlik veya gizlilik riski yaratan verileri önbelleğe almakten kaçının: sırlar (parolalar, API anahtarları), tek kullanımlık tokenlar (OTP kodları, parola sıfırlama tokenları) ve çevrimdışı erişim gerçekten gerekli değilse hassas kişisel veriler. Tam kart bilgilerini veya dolandırıcılığı kolaylaştıran hiçbir şeyi önbelleğe almayın.
Alışveriş uygulamasında ürün listesini önbelleğe almak büyük bir kazançtır. Ancak ödeme ekranı, satın alma işleminden hemen önce toplamları ve stok durumunu her zaman yenilemelidir.
Çoğu Flutter uygulaması ekranların hızlı yüklenmesi ve ağ beklerken boş görünmemesi için bir yerel önbelleğe ihtiyaç duyar. Kritik karar verinin nerede saklandığıdır; çünkü her katmanın hız, boyut sınırı ve temizleme davranışı farklıdır.
Hafıza (memory) önbelleği en hızlısıdır. Uygulama açık kaldığı sürece tekrar kullanılacak veriler için idealdir: mevcut kullanıcı profili, son arama sonuçları veya kullanıcı tarafından yeni görüntülenen bir ürün gibi. Dezavantajı açıktır: uygulama kapandığında kaybolur; soğuk başlatmalar veya çevrimdışı kullanım için yardımcı olmaz.
Diskte anahtar-değer depolama, yeniden başlatmalar arasında kalmasını istediğiniz küçük öğeler için uygundur. Tercihler ve küçük blob'lar: özellik bayrakları, "son seçilen sekme" ve nadiren değişen küçük JSON yanıtları. Bunu kasıtlı olarak küçük tutun. Büyük listeleri doğrudan anahtar-değer deposuna dökmeye başlarsanız güncellemeler karmaşıklaşır ve şişme kolay olur.
Yerel veritabanı, verileriniz daha büyük, yapılandırılmış veya çevrimdışı davranışa ihtiyaç duyuyorsa en iyisidir. Ayrıca sorgulara ihtiyaç olduğunda faydalıdır ("tüm okunmamış mesajlar", "sepetteki öğeler", "geçen ayın siparişleri")—büyük bir blob’u yükleyip hafızada filtrelemek yerine.
Önbelleklemenin öngörülebilir kalması için her veri türü için birincil depoyu seçin ve aynı dataset'i üç yerde tutmaktan kaçının.
Kısa bir kural:
Ayrıca boyutu planlayın. "Çok büyük"ün ne anlama geldiğine, öğeleri ne kadar süre saklayacağınıza ve nasıl temizleyeceğinize karar verin. Örneğin: önbelleğe alınmış arama sonuçlarını son 20 sorguyla sınırlayın ve 30 günden eski kayıtları düzenli olarak kaldırın ki önbellek sessizce büyümesin.
Yenileme kuralları her ekran için bir cümlede açıklanabilecek kadar basit olmalı. Mantıklı önbelleklemenin ödülü budur: kullanıcılar hızlı ekranlar elde eder ve uygulama güvenilir kalır.
En basit kural TTL (time to live). Veriyi bir zaman damgasıyla kaydedin ve örneğin 5 dakika boyunca taze sayın. Sonrasında eski olur. TTL, bir feed, kategoriler veya öneriler gibi "olması güzel" verilere uygundur.
Yararlı bir incelik soft TTL ve hard TTL ayrımıdır.
Soft TTL ile önbelleğe alınmış veriyi anında gösterirsiniz, sonra arka planda yenilersiniz ve değiştiyse UI'ı güncellersiniz. Hard TTL ile süre dolunca eski veriyi göstermeyi bırakırsınız. Ya yükleyiciyle engeller ya da "çevrimdışı/tekrar deneyin" durumunu gösterirsiniz. Hard TTL, yanlış olmanın yavaş olmasından daha kötü olduğu durumlar için uygundur: bakiyeler, sipariş durumu veya izinler gibi.
Eğer backend destekliyorsa, ETag, updatedAt veya bir versiyon alanı kullanarak "sadece değiştiyse yenile" yöntemini tercih edin. Uygulamanız "bu değişti mi?" diye sorup tam payload indirmeyi atlayabilir.
Kullanıcı dostu bir varsayılan çoğu ekran için stale-while-revalidate: hemen göster, sessizce yenile ve sadece sonuç farklıysa yeniden çiz. Bu hız verir, rastgele titremeyi önler.
Ekran bazlı tazelik genellikle şöyle olur:
Kuralları sadece çekme maliyetine değil, yanlış olmanın maliyetine göre seçin.
Önbellek geçersiz kılma şu soruyla başlar: hangi olay önbelleği yeniden çekme maliyetinden daha az güvenilir kılar? Küçük ve belirgin bir tetikleyici seti seçip ona bağlı kalırsanız davranış öngörülebilir olur ve UI sabit hisseder.
Gerçek uygulamalarda en çok önem taşıyan tetikleyiciler:
Örnek: kullanıcı profil fotoğrafını düzenledi, sonra geri döndü. Sadece zaman tabanlı yenilemeye güvenirseniz önceki ekran eski görüntüyü gösterebilir. Bunun yerine düzenlemeyi tetikleyici olarak görün: önbellekteki profile nesnesini hemen güncelleyin ve yeni bir zaman damgası ile taze işaretleyin.
Geçersiz kılma kurallarını küçük ve açık tutun. Eğer hangi olayın bir önbellek girişini geçersiz kıldığına tam olarak işaret edemiyorsanız, ya çok sık yenilersiniz (yavaş, titreyen UI) ya da gerekli zamanlarda yenilemezsiniz (eski ekranlar).
Öncelikle ana ekranlarınızı ve her birinin hangi veriye ihtiyaç duyduğunu listeleyin. Endpointler yerine kullanıcıya görünen nesneleri düşünün: profile, sepet, sipariş listesi, katalog öğesi, okunmamış sayaç.
Sonra her veri türü için bir tek gerçek kaynağı seçin. Flutter'da bu genellikle verinin nereden geldiğini (hafıza, disk, ağ) saklayan bir repository'dir. Ekranlar ne zaman ağa gidileceğine karar vermemeli; repository'den veri istemeli ve dönen duruma göre tepki vermeli.
Pratik bir akış:
Metadata kuralları zorunlu kılar. Eğer ownerUserId değişirse (çıkış/giriş), eski satırları hemen atabilir veya göz ardı edebilirsiniz; bu sayede önceki kullanıcının verisini kısa bir süre için göstermemiş olursunuz.
UI davranışı için "eski"nin ne anlama geldiğine önceden karar verin. Yaygın bir kural: eski veriyi anında göster ki ekran boş kalmasın, arka planda yenilemeyi başlat ve yeni veri gelince güncelle. Yenileme başarısız olursa eski veriyi tutun ve küçük, net bir hata gösterin.
Sonra kuralları birkaç sıkıcı testle kilitleyin:
İşte "bizde önbellekleme var" ile "uygulamamız her seferinde aynı davranıyor" arasındaki fark bu testlerdir.
Bir liste ekranında bir değeri görüp detaya girip onu düzenleyip geri döndüğünüzde eski değeri görmek güveni hızla zedeler. Navigasyon boyunca tutarlılık, her ekranın aynı kaynaktan okumasından gelir.
Sağlam bir kural: bir kere çek, bir kere kaydet, birçok kere render et. Ekranlar aynı endpointi bağımsız olarak çağırıp özel kopyalar tutmamalı. Önbelleğe alınmış veriyi paylaşan bir store (durum yönetimi katmanı) kullanın ve hem liste hem detay ekranlarının aynı veriyi izlemesine izin verin.
Mevcut değerin ve tazeliğin sahibi tek bir yer olsun. Ekranlar yenileme isteyebilir ama kendi zamanlayıcılarını, yeniden denemelerini ve ayrıştırmalarını yönetmemeli.
"İki gerçeklik"i önleyen pratik alışkanlıklar:
İyi kurallar olsa bile kullanıcılar bazen eski veriyi görecek (çevrimdışı, yavaş ağ, arka planda kalmış uygulama). Bunu küçük, sakin sinyallerle belli edin: "Az önce güncellendi" zaman damgası, ince bir "Yenileniyor…" göstergesi veya "Çevrimdışı" rozeti.
Düzenlemelerde iyimser (optimistic) güncellemeler genelde daha iyi hisseder. Örnek: kullanıcı detay ekranda bir ürün fiyatını değiştirir. Shared store'u hemen güncelleyin ki liste ekrana geri dönünce yeni fiyatı göstersin. Kayıt başarısız olursa önceki değere geri dönün ve kısa bir hata gösterin.
Çoğu önbellekleme hatası sıkıcıdır: önbellek çalışır ama kimse ne zaman kullanılacağını, ne zaman sona ereceğini ve kimin sahibi olduğunu açıklayamaz. En yaygın tuzak önbellekleme yapıp metadata eklememektir. Sadece payload saklarsanız onun eski olup olmadığını, hangi uygulama sürümünün ürettiğini veya hangi kullanıcıya ait olduğunu söyleyemezsiniz. En azından savedAt, basit bir versiyon numarası ve userId saklayın. Bu alışkanlık birçok "neden bu ekran yanlış?" hatasını engeller.
Başka bir yaygın sorun aynı verinin birden fazla cache'inin olmasıdır. Liste ekranı hafızada bir liste tutar, repository diske yazar ve detay ekran tekrar çekip başka bir yerde saklar. Bir kaynak belirleyin (genellikle repository katmanı) ve her ekranın oradan okumasını sağlayın.
Hesap değişiklikleri sık sık ayak kazasıdır. Biri çıkış yapıp başka hesapla giriş yaparsa kullanıcı fotoğrafı veya siparişleri kısa bir süre için eski kullanıcıya ait görünmemeli. Kullanıcıya ait tabloları ve anahtarları temizleyin.
Pratik düzeltmeler:
Örnek: ürün listeniz önbellekten anında yüklenir, sonra sessizce yenilenir. Yenileme başarısız olursa önbellek gösterilmeye devam eder ama kullanıcının verinin güncel olmayabileceğini açıkça gösterin ve Retry sunun. Yenileme sırasında UI'ı engellemeyin.
Yayın öncesi, önbellekleme "görünüşe göre iyi" halinden kuralları test edilebilir hale getirin. Kullanıcılar geri gelip giderken, çevrimdışıyken veya farklı bir hesapla giriş yaparken tutarlı veriler görmelidir.
Her ekran için verinin ne kadar süre taze kabul edileceğine karar verin. Hızlı değişen veriler için dakikalar (mesajlar, bakiyeler), yavaş değişen veriler için saatler (ayarlar, ürün kategorileri) olabilir. Sonra eski olduğunda ne olacağını onaylayın: arka plan yenileme, açılışta yenile veya manuel pull-to-refresh.
Her veri türü için hangi olayların önbelleği sileceğini veya atlayacağını kararlaştırın. Yaygın tetikleyiciler: çıkış, madde düzenleme, hesap değiştirme ve veri şekli değiştiren uygulama güncellemeleri.
Önbelleğe alınmış girdilerin yanında küçük bir metadata seti saklayın:
Sahipliği net tutun: her veri türü için bir repository kullanın (örneğin ProductsRepository), widget başına değil. Ayrıca çevrimdışı davranışı belirleyip test edin. Hangi ekranların önbellekten gösterileceğini, hangi eylemlerin devre dışı kalacağını ve göstereceğiniz metni ("Kaydedilmiş veriler gösteriliyor" ve görünür bir yenile düğmesi) netleştirin. Manuel yenileme her önbellek destekli ekranda kolay bulunur olmalı.
Basit bir mağaza uygulaması düşünün: ürün kataloğu (liste), ürün detayları ve Favoriler sekmesi. Kullanıcı katalogu kaydırır, bir ürünü açar ve kalp ikonuna dokunarak favoriler ekler. Hedef: yavaş ağlarda bile hızlı hissettirmek, aynı zamanda kafa karıştıran uyumsuzlukları göstermemek.
Anında render etmeye yardımcı olanları yerel olarak önbelleğe alın: katalog sayfaları (ID, başlık, fiyat, küçük resim URL'si, favori bayrağı), ürün detayları (açıklama, teknik bilgiler, bulunabilirlik, lastUpdated), resim metadata'sı (URL'ler, boyutlar, cache anahtarları) ve kullanıcının favorileri (ürün ID seti, opsiyonel zaman damgaları).
Kullanıcı katalogu açtığında önbelleğe alınmış sonuçları anında gösterin, sonra arka planda doğrulayın. Taze veri gelirse sadece değişenleri güncelleyin ve kaydırma pozisyonunu koruyun.
Favori açma/kapama eylemini "tutarlı olmak zorunda" kabul edin. Yerel favoriler setini hemen güncelleyin (optimistic update), sonra aynı ID için önbelleğe alınmış ürün satırlarını ve ürün detay önbelleklerini güncelleyin. Ağ çağrısı başarısız olursa geri alıp küçük bir mesaj gösterin.
Gezinmeyi tutarlı tutmak için liste rozeti ve detay kalp ikonunu aynı kaynak (yerel önbellek veya store) üzerinden yönetin, ayrı ekran durumlarından değil. Listeye geri döndüğünüzde kalp anında güncellenir, detay ekran listeden yapılan değişiklikleri yansıtır ve Favoriler sekmesi beklemeden doğru sayıyı gösterir.
Basit yenileme kuralları ekleyin: katalog önbelleği hızlıca sona erer (dakikalar), ürün detayları biraz daha uzun, favoriler süresiz saklanır ama giriş/çıkış sonrası her zaman reconcile edilir.
Önbellekleme, ekibinizin bir sayfa kurala işaret edip ne olacağını kabul ettiğinde gizemini kaybeder. Amaç mükemmellik değil; sürümler arasında aynı kalan öngörülebilir davranış.
Ekran başına küçük bir tablo yazın ve değişikliklerde gözden geçirilebilecek kadar kısa tutun: ekran adı ve ana veri, önbellek konumu ve anahtar, tazelik kuralı (TTL, olay tabanlı veya manuel), geçersiz kılma tetikleyicileri ve yenilenirken kullanıcıya ne gösterileceği.
Ayarlama yaparken hafif logging ekleyin. Önbellek isabetlerini, kaçırmalarını ve neden yenileme olduğunu kaydedin (TTL doldu, kullanıcı pull-to-refresh yaptı, uygulama geri geldi, mutation tamamlandı). Birisi "bu liste yanlış hissettiriyor" dediğinde bu loglar hatayı çözülebilir kılar.
Basit TTL'lerle başlayın, sonra kullanıcıların ne fark ettiğine göre ince ayar yapın. Bir haber akışı 5–10 dakika eski olabilir, oysa bir sipariş durumu ekranı geri gelince ve ödeme sonrası yenileme gerektirebilir.
Hızlı bir Flutter uygulaması inşa ediyorsanız, veri katmanınızı ve önbellek kurallarınızı uygulamadan önce tasarlamak yardımcı olur. Koder.ai (koder.ai) kullanan takımlar için planning mode, ekran başına kuralları yazmak ve sonra onlara göre inşa etmek için kullanışlıdır.
Yenileme davranışını ayarlarken kararlı ekranları koruyun. Yeni bir kural yanlışlıkla titreme, boş durumlar veya gezinti boyunca uyumsuz sayaçlar getirdiyse snapshot ve rollback işinizi kurtarabilir.
Start with one clear rule per screen: what it may show immediately (cached), when it must refresh, and what the user sees during refresh. If you can’t explain the rule in one sentence, the app will eventually feel inconsistent.
Treat cached data as having a freshness state. If it’s fresh, show it. If it’s stale but usable, show it now and refresh quietly. If it’s must refresh, fetch before showing (or show a loading/offline state). This keeps your UI behavior consistent instead of “sometimes it updates, sometimes it doesn’t.”
Cache things that are read often and can be slightly old without harming the user, like feeds, catalogs, reference data, and basic profile info. Be careful with money- or time-critical data like balances, stock, ETAs, and order status; you can cache it for speed, but force a refresh right before a decision or confirmation step.
Use memory for fast reuse during the current session, like the current profile or recently viewed items. Use disk key-value storage for small, simple items that should survive restarts, like preferences. Use a database when data is large, structured, needs queries, or should work offline, like messages, orders, or an inventory list.
A plain TTL is a good default: consider data fresh for a set time, then refresh. For many screens, a better experience is “show cached now, refresh in the background, then update if changed,” because it avoids blank screens and reduces flicker.
Invalidate on events that clearly change trust in the cache: user edits (create/update/delete), login/logout or account switching, app resume if data is older than your TTL, and explicit user refresh. Keep these triggers small and explicit so you don’t end up refreshing constantly or never refreshing when it matters.
Make both screens read from the same source of truth, not their own private copies. When the user edits something on the details screen, update the shared cached object immediately so the list renders the new value on back navigation, then sync with the server and roll back only if the save fails.
Always store metadata next to the payload, especially a timestamp and a user identifier. On logout or account switch, clear or isolate user-scoped cache entries immediately and cancel in-flight requests tied to the old user so you don’t briefly render the previous user’s data.
Default to keeping stale data visible and show a small, clear error state that offers retry, rather than blanking the screen. If the screen can’t safely show old data, switch to a must-refresh rule and show a loading or offline message instead of pretending the stale value is trustworthy.
Put cache rules in your data layer (for example, repositories) so every screen follows the same behavior. If you’re building quickly in Koder.ai, write the per-screen freshness and invalidation rules in planning mode first, then implement so the UI simply reacts to states instead of inventing its own refresh logic.