Riverpod — Flutter-এর জন্য কম্পাইলড ডিপেনডেন্সি ম্যানেজমেন্ট

লেখক: IT Sectr প্রকাশিত: 2026-02-19 পড়ার সময়: 7 মিনিট

Riverpod — Flutter-এর জন্য একটি কম্পাইলড স্টেট এবং ডিপেনডেন্সি ম্যানেজার, যা Remi Rousselet 2021 সালে Provider-এর উত্তরসূরি হিসেবে তৈরি করেছেন। Riverpod Provider-এর মৌলিক সমস্যাগুলো সমাধান করে: কম্পাইল-টাইম চেকিংয়ের অভাব, BuildContext-এর উপর নির্ভরশীলতা এবং ProviderNotFoundException-এর জটিলতা। pub.dev-এর তথ্য অনুসারে, প্যাকেজটি ৫ হাজারের বেশি লাইক পেয়েছে এবং নতুন প্রজেক্টে Provider-কে সক্রিয়ভাবে প্রতিস্থাপন করছে।

মূল বিষয়

  • ProviderRef — একটি প্রোভাইডারের ভিতরে অন্য প্রোভাইডারগুলো অ্যাক্সেস করার জন্য অবজেক্ট
  • AsyncValue — loading/error/data অবস্থাসহ অ্যাসিঙ্ক্রোনাস ডেটার জন্য র্যাপার
  • Notifier — মিউটেশন মেথডসহ মিউটেবল স্টেটের জন্য ক্লাস
  • ProviderScope — মূল উইজেট যা সব প্রোভাইডার পরিচালনা করে
  • Code Generation — স্বয়ংক্রিয় প্রোভাইডার জেনারেশনের জন্য @riverpod অ্যানোটেশন

Riverpod কী?

Riverpod Flutter-এর জন্য একটি স্টেট ম্যানেজমেন্ট এবং ডিপেনডেন্সি ইনজেকশন লাইব্রেরি যা প্রোভাইডার বর্ণনাকে নিরাপদ Dart কোডে কম্পাইল করে। Provider-এর বিপরীতে, Riverpod প্রোভাইডারগুলো BuildContext-এর সাথে আবদ্ধ নয়: এগুলি গ্লোবালি বা ProviderScope-এ তৈরি করা হয় এবং যেকোনো জায়গা থেকে অ্যাক্সেসযোগ্য। কম্পাইলার বিল্ড টাইমে টাইপ, ডিপেনডেন্সি এবং প্রোভাইডার গ্রাফের অখণ্ডতা পরীক্ষা করে, যার ফলে ProviderNotFoundException-এর মতো রানটাইম ত্রুটি দূর হয়।

Riverpod টেস্টিংয়ের জন্য override মডেল ব্যবহার করে: প্রতিটি প্রোভাইডারকে ProviderScope.overrideWith-এর মাধ্যমে সাবক্লাস তৈরি বা ইন্টারফেস মক না করেই ওভাররাইড করা যায়। এটি টেস্টিংকে বিচ্ছিন্ন করে: প্রতিটি টেস্ট ডিপেনডেন্সি গ্রাফের নিজস্ব কপি পায় যা সম্পূর্ণ নিয়ন্ত্রিত।

Flutter Community Survey 2025-এর তথ্য অনুসারে, Riverpod Provider এবং BLoC-এর পরে জনপ্রিয়তায় তৃতীয় স্থানে রয়েছে। তবে Riverpod হল সবচেয়ে দ্রুত বর্ধনশীল প্যাকেজ: 2024-এ +120% ইনস্টল। প্রধান কারণ: কম্পাইল-টাইম নিরাপত্তা, কোন ProviderNotFoundException নেই, AsyncValue-এর মাধ্যমে বিল্ট-ইন অ্যাসিঙ্ক সমর্থন।

প্রোভাইডারের প্রকারভেদ

Riverpod ৮ ধরনের প্রোভাইডার প্রদান করে, প্রতিটি নির্দিষ্ট পরিস্থিতির জন্য: Provider (ধ্রুবক/সেবা), StateProvider (আদিম অবস্থা), StateNotifierProvider (StateNotifier-সহ জটিল লজিক), ChangeNotifierProvider (Provider থেকে মাইগ্রেশনের জন্য), FutureProvider (অ্যাসিঙ্ক ডেটা, একবার), StreamProvider (রিঅ্যাকটিভ স্ট্রিম), NotifierProvider (নতুন API, Flutter 3.10+) এবং AsyncNotifierProvider (অ্যাসিঙ্ক Notifier)।

Dart
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
  void decrement() => state--;
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}

ProviderRef — অন্যান্য প্রোভাইডার অ্যাক্সেস করার জন্য প্রতিটি প্রোভাইডারে পাস করা অবজেক্ট। ref.watch — পরিবর্তনের সাবস্ক্রিপশন, ref.read — একবার পড়া, ref.invalidate — ক্যাশ রিসেট। ProviderRef Provider-এর BuildContext প্রতিস্থাপন করে: যেকোনো প্রোভাইডার উইজেট ট্রিতে অ্যাক্সেস ছাড়াই অন্য প্রোভাইডার পড়তে পারে। এটি UI লেয়ারের বাইরে ডিপেনডেন্সি গ্রাফ তৈরি করতে দেয়।

ProviderScope — মূল উইজেট, Riverpod কাজ করার জন্য বাধ্যতামূলক। ProviderScope সব প্রোভাইডার সংরক্ষণ করে, তাদের লাইফসাইকেল পরিচালনা করে এবং মান ক্যাশ করে। ProviderScope ছাড়া অ্যাপ ProviderNotFoundException-সহ ক্র্যাশ করবে। ProviderScope নেস্টেড হতে পারে — নেস্টেড স্কোপ প্যারেন্ট প্রোভাইডার ওভাররাইড করে, যা টেস্টিং এবং ফিচার আইসোলেশনের জন্য ব্যবহৃত হয়।

AsyncValue এবং অ্যাসিঙ্ক্রোনাসিটি নিয়ে কাজ

AsyncValue — অ্যাসিঙ্ক্রোনাস অবস্থা উপস্থাপনের জন্য Riverpod-এর সিলড ক্লাস। AsyncValue-এর তিনটি রূপ আছে: AsyncData (সফল ডেটা), AsyncError (ত্রুটি), AsyncLoading (লোড হচ্ছে)। loading/error/data-এর মধ্যে ম্যানুয়ালি স্যুইচ করার পরিবর্তে, প্রতিটি FutureProvider বা StreamProvider স্বয়ংক্রিয়ভাবে AsyncValue রিটার্ন করে, এবং উইজেট ref.watch-এর মাধ্যমে তিনটি অবস্থাই হ্যান্ডল করে।

Dart
final userProvider = FutureProvider((ref) async {
  final api = ref.watch(apiProvider);
  return await api.fetchUser();
});

class UserScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsync = ref.watch(userProvider);
    return userAsync.when(
      data: (user) => UserWidget(user),
      error: (e, _) => ErrorWidget(e.toString()),
      loading: () => CircularProgressIndicator(),
    );
  }
}

AsyncValue.when — তিনটি অবস্থার প্যাটার্ন-ম্যাচিংয়ের জন্য মেথড। কম্পাইলার পরীক্ষা করে যে তিনটি ক্ষেত্রেই হ্যান্ডল করা হয়েছে — যদি আপনি loading বা error ভুলে যান, কোড কম্পাইল হবে না। AsyncValue.whenData — শুধুমাত্র ডেটার জন্য (যদি loading/error প্রয়োজন না হয়)। AsyncValue.guard — ব্যতিক্রমকে AsyncError-এ রূপান্তরের জন্য try-catch-এর উপর র্যাপার। keepAlive — একটি ফ্ল্যাগ যা প্রোভাইডার ক্যাশকে স্কোপের বাইরে যাওয়ার সময় ধ্বংস হতে বাধা দেয়।

কোড জেনারেশন এবং @riverpod

কোড জেনারেশন — Riverpod 2.0+-এর একটি মূল বৈশিষ্ট্য। ফাংশনে @riverpod অ্যানোটেশন স্বয়ংক্রিয়ভাবে সঠিক টাইপ, রিফ্যাক্টরিং সাপোর্ট এবং অটোকমপ্লিট-সহ একটি প্রোভাইডার জেনারেট করে। কোড জেনারেশন riverpod_generator এবং build_runner ব্যবহার করে। ডেভেলপার একটি পিওর ফাংশন লেখে, এবং বাকি সবকিছু — টাইপ, ক্লাস, ফ্যাক্টরি কনস্ট্রাক্টর — স্বয়ংক্রিয়ভাবে জেনারেট হয়।

Dart
@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello World';
}

// জেনারেটেড: final helloWorldProvider = Provider((ref) => 'Hello World');

@riverpod
class Counter extends _$Counter {
  int build() => 0;
  void increment() => state++;
}

Notifier — কোড জেনারেশন-সহ মিউটেবল স্টেটের জন্য নতুন API। Notifier একটি build() মেথড এবং স্টেট মিউটেশন মেথডসহ ক্লাস। StateNotifier-এর বিপরীতে, Notifier-এর আলাদা স্টেট ক্লাসের প্রয়োজন হয় না এবং getter/setter-এর মাধ্যমে state-তে সরাসরি অ্যাক্সেস দেয়। Riverpod @riverpod দিয়ে অ্যানোটেটেড প্রতিটি Notifier ক্লাসের জন্য স্বয়ংক্রিয়ভাবে NotifierProvider জেনারেট করে।

build_runner: কোড জেনারেশন dart run build_runner build কমান্ড দিয়ে চালানো হয়। জেনারেটেড ফাইলগুলোর .g.dart সাফিক্স থাকে এবং সোর্স কোডে ইমPORT করা হয়। যখন অ্যানোটেশন বা প্রোভাইডার টাইপ পরিবর্তন হয়, তখন কোড জেনারেশন পুনরায় চালানোর প্রয়োজন হয়। Riverpod 2.x সব নতুন প্রজেক্টের জন্য কোড জেনারেশন সুপারিশ করে — ম্যানুয়াল প্রোভাইডার তৈরি অপ্রচলিত হচ্ছে।

Riverpod বনাম Provider

মূল পার্থক্য Riverpod এবং Provider-এর মধ্যে: BuildContext থেকে স্বাধীনতা, কম্পাইল-টাইম নিরাপত্তা, বিল্ট-ইন অ্যাসিঙ্ক সাপোর্ট, অটো-ক্যাশিং এবং override-এর মাধ্যমে টেস্টিং। Provider-এর স্টেট অ্যাক্সেস করতে BuildContext প্রয়োজন (context.watch, context.read), Riverpod WidgetRef এবং গ্লোবালি ডিক্লেয়ারড প্রোভাইডার ব্যবহার করে।

বৈশিষ্ট্যProviderRiverpod
BuildContext নির্ভরতাহ্যাঁনা
কম্পাইল-টাইম চেকনাহ্যাঁ (@riverpod-এর মাধ্যমে)
ProviderNotFoundExceptionরানটাইমঅসম্ভব
অ্যাসিঙ্ক্রোনাসিটিম্যানুয়ালAsyncValue (বিল্ট-ইন)
টেস্টিংProvider-এ র্যাপারProviderScope.overrideWith
ক্যাশিংনাস্বয়ংক্রিয় + keepAlive

Provider থেকে মাইগ্রেশন: Riverpod পুনর্লিখন ছাড়াই বিদ্যমান ChangeNotifier ব্যবহারের জন্য ChangeNotifierProvider.adaptive সমর্থন করে। ধাপে ধাপে মাইগ্রেশন: প্রথমে নতুন ফিচার Riverpod-এ লেখা হয়, তারপর পুরনো Provider ইন্সট্যান্স অ্যাডাপ্টারের মাধ্যমে Riverpod প্রোভাইডার দিয়ে প্রতিস্থাপন করা হয়। উভয় প্যাকেজ একটি প্রজেক্টে সহাবস্থান করতে পারে, যা ডেভেলপমেন্ট স্থগিত না করেই মাইগ্রেট করতে দেয়।

Riverpod টেস্টিং

Riverpod টেস্টিং ProviderScope.overrideWith-এর উপর ভিত্তি করে তৈরি। প্রতিটি প্রোভাইডার মক বা DI কন্টেইনার ছাড়াই একটি টেস্ট ProviderScope-এর ভিতরে ওভাররাইড করা হয়। ProviderContainer — Flutter ছাড়া টেস্টের জন্য বিচ্ছিন্ন পরিবেশ (বিশুদ্ধ Dart), যা উইজেট রেন্ডারিং ছাড়াই প্রোভাইডার টেস্ট করতে দেয়।

Dart
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';

void main() {
  test('Counter increments correctly', () {
    final container = ProviderContainer();
    container.read(counterProvider.notifier).increment();
    expect(container.read(counterProvider), 1);
  });

  testWidgets('UI updates on increment', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [counterProvider.overrideWithValue(5)],
        child: CounterScreen(),
      ),
    );
    expect(find.text('5'), findsOneWidget);
  });
}

ProviderContainer — Flutter ছাড়া। উইজেট ছাড়া প্রোভাইডারের ইউনিট টেস্টের জন্য ProviderContainer ব্যবহার করুন। overrideWithValue — একটি নির্দিষ্ট মান দিয়ে প্রোভাইডার প্রতিস্থাপন করা। overrideWith — প্রোভাইডার ফ্যাক্টরি দিয়ে প্রতিস্থাপন করা (সেবা মক করার জন্য)। autodispose — টেস্টে পরীক্ষা করুন যে প্রোভাইডার container.dispose() ব্যবহার করে স্কোপের বাইরে গেলে ধ্বংস হয়।

সচরাচর জিজ্ঞাসিত প্রশ্ন

Riverpod BLoC থেকে কীভাবে আলাদা?

Riverpod হল একটি স্টেট ম্যানেজমেন্ট লাইব্রেরি যা গ্লোবাল প্রোভাইডার, AsyncValue এবং কোড জেনারেশন-সহ। BLoC হল Event → Stream → State-সহ একটি আর্কিটেকচারাল প্যাটার্ন। Riverpod শেখা সহজ এবং @riverpod অ্যানোটেশনের মাধ্যমে উন্নত DX প্রদান করে। BLoC কঠোর বিজনেস লজিক আইসোলেশন এবং BlocObserver-এর মাধ্যমে Event ট্রেসিং প্রদান করে। পছন্দ প্রজেক্ট প্যারাডাইমের উপর নির্ভর করে: Riverpod Provider-এর কাছাকাছি, BLoC — রিঅ্যাকটিভ স্ট্রিমের কাছাকাছি।

Riverpod-এ autodispose কী?

Autodispose হল একটি প্রক্রিয়া যা স্বয়ংক্রিয়ভাবে একটি প্রোভাইডার ধ্বংস করে যখন কেউ এতে সাবস্ক্রাইব করা থাকে না। ডিফল্টভাবে, সব Riverpod প্রোভাইডার autodispose করে: যখন একটি উইজেট ট্রি থেকে বেরিয়ে যায়, প্রোভাইডার মেমোরি থেকে সরিয়ে ফেলা হয়। keepAlive — একটি ফ্ল্যাগ যা সেই প্রোভাইডারগুলোর জন্য autodispose নিষ্ক্রিয় করে যাদের সবসময় জীবিত থাকা উচিত (API ক্লায়েন্ট, রিপোজিটরি, সেটিংস)। এটি মেমোরি লিক প্রতিরোধ করে — অব্যবহৃত প্রোভাইডার স্বয়ংক্রিয়ভাবে ধ্বংস হয়।

ref.invalidate কীভাবে কাজ করে?

ref.invalidate — একটি মেথড যা জোর করে প্রোভাইডার ক্যাশ রিসেট করে। invalidate-এর পর, পরবর্তী পড়ায় প্রোভাইডার পুনরায় তৈরি হয়: FutureProvider অ্যাসিঙ্ক ফাংশন পুনরায় নির্বাহ করে, StreamProvider স্ট্রিমে পুনরায় সাবস্ক্রাইব করে। ডেটা রিফ্রেশ বাধ্য করতে invalidate ব্যবহার করুন (pull-to-refresh, ব্যবহারকারী পরিবর্তন)। ref.refresh — invalidate + পড়ার সংমিশ্রণ: একটি অপারেশনে রিসেট করে এবং তাৎক্ষণিকভাবে নতুন মান পড়ে।

কোড জেনারেশন ছাড়া Riverpod ব্যবহার করা যাবে কি?

হ্যাঁ। Riverpod 1.x শুধুমাত্র কোড জেনারেশন ছাড়া কাজ করে — প্রোভাইডার ম্যানুয়ালি Provider(), StateNotifierProvider(), FutureProvider() ইত্যাদি ব্যবহার করে তৈরি করা হয়। Riverpod 2.x উভয় পদ্ধতি সমর্থন করে। কোড জেনারেশন ছাড়া আরও boilerplate আছে কিন্তু build_runner এবং dart run build_runner build-এর উপর কোনো নির্ভরতা নেই। ছোট প্রজেক্টের (৩০টি প্রোভাইডার পর্যন্ত) জন্য ম্যানুয়াল তৈরি যুক্তিসঙ্গত; বড় প্রজেক্টের জন্য কোড জেনারেশন বাধ্যতামূলক।

Family প্রোভাইডার কী?

Family — একটি প্রোভাইডার মডিফায়ার যা বাহ্যিক প্যারামিটার গ্রহণ করে। উদাহরণস্বরূপ, userProvider(123) — একটি প্রোভাইডার যা ID 123-সহ ব্যবহারকারী লোড করে। Family প্রোভাইডার প্রতিটি অনন্য প্যারামিটারের জন্য আলাদাভাবে ফলাফল ক্যাশ করে। আইটেমের তালিকার জন্য Family ব্যবহার করুন যেখানে প্রতিটি আইটেম ID দ্বারা লোড করা হয়। Family মডিফায়ার সব ধরনের প্রোভাইডারের জন্য উপলব্ধ: Provider.family, FutureProvider.family, StreamProvider.family।

সারসংক্ষেপ

  • Riverpod — একটি কম্পাইলড স্টেট ম্যানেজার, ProviderNotFoundException ছাড়া Provider-এর উত্তরসূরি
  • ProviderRef — অন্যান্য প্রোভাইডারের ভিতরে প্রোভাইডার অ্যাক্সেসের জন্য BuildContext-এর বিকল্প
  • AsyncValue — অ্যাসিঙ্ক্রোনাস ডেটার জন্য loading/error/data অবস্থাসহ সিলড ক্লাস
  • @riverpod কোড জেনারেশন — স্বয়ংক্রিয় টাইপ ইনফারেন্স এবং প্রোভাইডার ফ্যাক্টরি
  • ProviderScope.overrideWith — মক এবং DI কন্টেইনার ছাড়া বিচ্ছিন্ন টেস্টিং
  • Family — পৃথক ক্যাশিং-সহ প্যারামিটারাইজড প্রোভাইডার
  • autodispose এবং keepAlive — স্বয়ংক্রিয় প্রোভাইডার লাইফসাইকেল ম্যানেজমেন্ট

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন