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!',
);
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.
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.watchnedeniyle 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:
- riverpod
- riverpod_generator
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;
});
Stream<int> example(Ref 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;
}
ref.onDispose geri çağırması yan etki tetiklememelidir.
onDispose içinde provider'ları değiştirmek beklenmedik davranışlara yol açabilir.
Ş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.
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'),
);
}
}
Provider'lar ref.invalidateSelf kullanarak kendilerini de geçersiz kılabilir.
Ancak bu durumda sonuç her zaman yeni bir durumun oluşturulması olur.
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:
- riverpod
- riverpod_generator
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'));
}
String label(Ref ref, String userName) {
return 'Hello $userName';
}
// ...
void onTap() {
// Bu provider'ın olası tüm parametre kombinasyonlarını geçersiz kıl.
ref.invalidate(labelProvider);
// Yalnızca belirli bir kombinasyonu geçersiz kıl
ref.invalidate(labelProvider('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.
- riverpod
- riverpod_generator
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;
});
Future<String> example(Ref 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.
ref.keepAlive();
// Otomatik yok etme davranışını geri getirmek için `link`i şöyle kullanabiliriz:
// link.close();
return response.body;
}
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:
- riverpod
- riverpod_generator
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'));
});
Future<Object> example(Ref 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.