Ana içeriğe atla

Otomatik yok etme

Riverpod'da, bir provider artık kullanılmadığında onunla ilişkili kaynakları otomatik olarak yok etmesini framework'e söyleyebilirsiniz.

Otomatik yok etmeyi etkinleştirmek/devre dışı bırakmak

Kod üretimi kullanıyorsanız bu özellik varsayılan olarak etkindir ve anotasyon üzerinden devre dışı bırakılabilir:

// Otomatik yok etmeyi devre dışı bırak
(keepAlive: true)
String helloWorld(Ref ref) => 'Hello world!';

Kod üretimi kullanmıyorsanız, provider'ı oluştururken isAutoDispose: true belirterek etkinleştirebilirsiniz:

final helloWorldProvider = Provider<String>(
// Otomatik yok etmeyi devreye al
isAutoDispose: true,
(ref) => 'Hello world!',
);
NOT

Otomatik yok etmeyi etkinleştirmek ya da devre dışı bırakmak, provider yeniden hesaplandığında durumun yok edilip edilmeyeceğini etkilemez.
Provider yeniden hesaplandığında durum her zaman yok edilir.

DİKKAT

Provider'lar parametre aldığında otomatik yok etmeyi etkinleştirmeniz önerilir. Aksi takdirde her parametre kombinasyonu için ayrı bir durum oluşturulur ve bu da bellek sızıntılarına yol açabilir.

Otomatik yok etme ne zaman tetiklenir?

Otomatik yok etme etkinken Riverpod, bir provider'ın dinleyicisi olup olmadığını takip eder. Bu takip, Ref.watch/Ref.listen çağrıları (ve birkaç benzeri çağrı) üzerinden yapılır.

Bu sayaç sıfıra ulaştığında provider "kullanılmıyor" kabul edilir ve Ref.onCancel tetiklenir. Bu noktada Riverpod bir kare bekler (bkz. await null). O kareden sonra provider hâlâ kullanılmıyorsa provider yok edilir ve Ref.onDispose tetiklenir.

Durumun yok edilmesine tepki vermek

Riverpod'da bir durumun yok edilmesi için birkaç yerleşik yol vardır:

  • Provider artık kullanılmıyordur ve "auto dispose" modundadır (buna birazdan değineceğiz). Bu durumda provider ile ilişkili tüm durum yok edilir.
  • Provider, örneğin ref.watch nedeniyle yeniden hesaplanır. Bu durumda önceki durum yok edilir ve yeni bir durum oluşturulur.

Her iki durumda da bu gerçekleştiğinde bir miktar mantık çalıştırmak isteyebilirsiniz.
Bunu ref.onDispose ile yapabilirsiniz. Bu metot, durum her yok edildiğinde çalışacak bir dinleyici kaydetmenizi sağlar.

Örneğin, etkin bir StreamController'ı kapatmak için kullanabilirsiniz:

final provider = StreamProvider<int>((ref) {
final controller = StreamController<int>();

// Durum yok edildiğinde StreamController'ı kapatıyoruz.
ref.onDispose(controller.close);

// YAPILACAK: StreamController'a birkaç değer gönderin
return controller.stream;
});
DİKKAT

ref.onDispose geri çağırması yan etki tetiklememelidir. onDispose içinde provider'ları değiştirmek beklenmedik davranışlara yol açabilir.

bilgi

Şunlar gibi başka kullanışlı yaşam döngüsü metotları da vardır:

  • ref.onCancel, bir provider'ın son dinleyicisi kaldırıldığında çağrılır.
  • ref.onResume, onCancel çağrıldıktan sonra yeni bir dinleyici eklendiğinde çağrılır.
bilgi

ref.onDisposeu istediğiniz kadar çağırabilirsiniz. Provider'ınızdaki yok edilebilir her nesne için bir kez çağırmaktan çekinmeyin. Bu alışkanlık, bir şeyi yok etmeyi unuttuğumuzda bunu fark etmeyi kolaylaştırır.

ref.invalidate ile bir provider'ın yok edilmesini elle zorlamak

Bazen bir provider'ın yok edilmesini zorlamak isteyebilirsiniz. Bu, başka bir provider'dan ya da bir widget'tan çağrılabilen ref.invalidate ile yapılabilir.

ref.invalidate kullanmak provider'ın mevcut durumunu yok eder. Ardından iki olası sonuç vardır:

  • Provider dinleniyorsa yeni bir durum oluşturulur.
  • Provider dinlenmiyorsa provider tamamen yok edilir.
class MyWidget extends ConsumerWidget {

Widget build(BuildContext context, WidgetRef ref) {
return ElevatedButton(
onPressed: () {
// Tıklandığında provider'ı yok et.
ref.invalidate(someProvider);
},
child: const Text('dispose a provider'),
);
}
}
bilgi

Provider'lar ref.invalidateSelf kullanarak kendilerini de geçersiz kılabilir. Ancak bu durumda sonuç her zaman yeni bir durumun oluşturulması olur.

ipucu

Parametre alan bir provider'ı geçersiz kılmaya çalışırken, ister tek bir parametre kombinasyonunu, ister tüm parametre kombinasyonlarını tek seferde geçersiz kılabilirsiniz:

final provider = Provider.autoDispose.family<String, String>((ref, name) {
return 'Hello $name';
});

// ...

void onTap() {
// Bu provider'ın olası tüm parametre kombinasyonlarını geçersiz kıl.
ref.invalidate(provider);
// Yalnızca belirli bir kombinasyonu geçersiz kıl
ref.invalidate(provider('John'));
}

ref.keepAlive ile ince ayarlı yok etme

Yukarıda belirtildiği gibi, otomatik yok etme etkinken provider'ın bir kare boyunca hiç dinleyicisi kalmadığında durum yok edilir.

Ancak bu davranış üzerinde daha fazla denetim isteyebilirsiniz. Örneğin, başarılı ağ isteklerinin durumunu saklamak ama başarısız istekleri önbelleğe almamak isteyebilirsiniz.

Bu, otomatik yok etmeyi etkinleştirdikten sonra ref.keepAlive ile yapılabilir. Bunu kullanarak durumun ne zaman otomatik olarak yok edilmeyi bırakacağına karar verebilirsiniz.

final provider = FutureProvider.autoDispose<String>((ref) async {
final response = await http.get(Uri.parse('https://example.com'));
// Provider'ı yalnızca istek başarıyla tamamlandıktan sonra canlı tutuyoruz.
// İstek başarısız olursa (ve bir istisna fırlatırsa), provider dinlenmeyi
// bıraktığında durum yok edilecektir.
final link = ref.keepAlive();

// Otomatik yok etme davranışını geri getirmek için `link`i şöyle kullanabiliriz:
// link.close();

return response.body;
});
NOT

Provider yeniden hesaplanırsa otomatik yok etme yeniden etkinleşir.

Ayrıca ref.keepAlivein dönüş değerini kullanarak otomatik yok etmeye geri dönmek de mümkündür.

Örnek: durumu belirli bir süre boyunca canlı tutmak

Riverpod şu anda durumu belirli bir süre boyunca canlı tutmak için yerleşik bir yol sunmuyor.
Ancak böyle bir özelliği şimdiye kadar gördüğümüz araçlarla uygulamak hem kolay hem de yeniden kullanılabilir.

Bir Timer ile ref.keepAlivei birlikte kullanarak durumu belirli bir süre canlı tutabiliriz. Bu mantığı yeniden kullanılabilir hale getirmek için bir uzantı (extension) metodu olarak yazabiliriz:

extension CacheForExtension on Ref {
/// Provider'ı [duration] süresince canlı tutar.
void cacheFor(Duration duration) {
// Durumun yok edilmesini anında engelliyoruz.
final link = keepAlive();
// Süre dolduktan sonra otomatik yok etmeyi yeniden etkinleştiriyoruz.
final timer = Timer(duration, link.close);

// İsteğe bağlı: provider yeniden hesaplandığında (örneğin ref.watch ile),
// bekleyen zamanlayıcıyı iptal ediyoruz.
onDispose(timer.cancel);
}
}

Ardından bunu şu şekilde kullanabiliriz:

final provider = FutureProvider.autoDispose<Object>((ref) async {
/// Durumu 5 dakika boyunca canlı tutar
ref.cacheFor(const Duration(minutes: 5));

return http.get(Uri.https('example.com'));
});

Bu mantığı ihtiyaçlarınıza göre uyarlayabilirsiniz. Örneğin, bir provider belirli bir süre boyunca dinlenmediyse durumu yok etmek için ref.onCancel/ref.onResume kullanabilirsiniz.