StreamBuilder একটি Flutter উইজেট যা অ্যাসিঙ্ক্রোনাস স্ট্রিম থেকে নতুন ডেটা পাওয়ার সময় স্বয়ংক্রিয়ভাবে ইন্টারফেস পুনর্নির্মাণ করে। FutureBuilder-এর বিপরীতে, যা একক ফলাফলের সাথে কাজ করে, StreamBuilder স্ট্রিমের পুরো জীবনচক্র জুড়ে UI-এর ক্রমাগত আপডেট সমর্থন করে। অফিসিয়াল Flutter ডকুমেন্টেশন (2026) অনুযায়ী, StreamBuilder রিয়েল-টাইম অ্যাপ্লিকেশনে ব্যবহৃত হয়: চ্যাট, নিউজ ফিড, সেন্সর মনিটরিং এবং ফাইন্যান্সিয়াল টিকার। এটি রিঅ্যাকটিভ প্রোগ্রামিংয়ের একটি মূল হাতিয়ার, যেখানে UI ম্যানুয়াল setState কল ছাড়াই ডেটার অবস্থা প্রতিফলিত করে।
মূল বিষয়
StreamBuilder Flutter SDK প্যাকেজের একটি উইজেট যা একটি Stream-এ সাবস্ক্রাইব করে এবং প্রতিটি নতুন স্ট্রিম ইভেন্টে তার চাইল্ড এলিমেন্ট পুনর্নির্মাণ করে। StreamBuilder একটি Stream অবজেক্ট গ্রহণ করে এবং স্ট্রিম থেকে প্রাপ্ত সর্বশেষ স্ন্যাপশটের ভিত্তিতে একটি উইজেট ফেরত দেয়।
Flutter আর্কিটেকচারে, StreamBuilder Builder উইজেটের গ্রুপের অন্তর্ভুক্ত যা UI নির্মাণকে ডেটা অবস্থা থেকে পৃথক করে। StatefulWidget-এর বিপরীতে, যেখানে অবস্থা পরিবর্তনের জন্য স্পষ্ট setState কল প্রয়োজন, StreamBuilder অ্যাসিঙ্ক্রোনাস ইভেন্টে স্বয়ংক্রিয়ভাবে প্রতিক্রিয়া জানায়, যা কোড সরল করে এবং সিঙ্ক্রোনাইজেশন ত্রুটির ঝুঁকি হ্রাস করে।
FutureBuilder-এর বিপরীতে, যা একটি একক অ্যাসিঙ্ক্রোনাস মান হ্যান্ডেল করে, StreamBuilder ক্রমাগত ডেটা স্ট্রিমের জন্য ডিজাইন করা হয়েছে। FutureBuilder প্রথম ফলাফল পাওয়ার পর সমাপ্ত হয়, যেখানে StreamBuilder স্ট্রিম শুনতে থাকে এবং প্রতিটি নতুন ইভেন্টে UI আপডেট করে।
StreamBuilder সব পরিস্থিতিতে ব্যবহৃত হয় যেখানে ডেটা ক্রমাগত আসে: WebSocket সংযোগ, সেন্সর কলব্যাক, Firebase বিজ্ঞপ্তি, Bluetooth ইভেন্ট কিউ, এবং BLoC-এর মাধ্যমে অ্যাপ্লিকেশন অবস্থা সম্প্রচার। GitHub-এ Flutter প্রকল্পের বিশ্লেষণ (2025) অনুযায়ী, StreamBuilder FutureBuilder এবং LayoutBuilder-এর সাথে সবচেয়ে বেশি ব্যবহৃত তিনটি Builder উইজেটের মধ্যে একটি।
সারসংক্ষেপ: StreamBuilder ব্যবহার করুন যেখানে UI-কে ক্রমাগত পরিবর্তনশীল ডেটা প্রতিফলিত করতে হবে, StatefulWidget-এর মাধ্যমে ম্যানুয়াল অবস্থা পরিচালনা এড়িয়ে।
StreamBuilder বিল্ড সময়ে একটি Stream-এ সাবস্ক্রাইব করে এবং উইজেট ধ্বংস হলে আনসাবস্ক্রাইব করে। প্রতিবার Stream একটি ইভেন্ট নির্গত করলে, StreamBuilder একটি নতুন AsyncSnapshot পায় এবং UI পুনর্নির্মাণের জন্য builder ফাংশন কল করে।
প্রক্রিয়াটি তিনটি ধাপ নিয়ে গঠিত। প্রথম: StreamBuilder stream.listen পদ্ধতির মাধ্যমে পাসকৃত Stream-এ সাবস্ক্রিপশন তৈরি করে। দ্বিতীয়: প্রতিটি ইভেন্টে, StreamBuilder অভ্যন্তরীণ AsyncSnapshot আপডেট করে এবং পুনর্নির্মাণের জন্য উইজেটটিকে নোংরা হিসেবে চিহ্নিত করে। তৃতীয়: ফ্রেমওয়ার্ক builder ফাংশনকে নতুন স্ন্যাপশটের সাথে কল করে, এবং UI বর্তমান ডেটা প্রদর্শন করে।
গুরুত্বপূর্ণ: StreamBuilder অভ্যন্তরীণভাবে StreamSubscription ব্যবহার করে। যদি Stream সরাসরি পাস করা হয়, StreamBuilder আরম্ভের সময় একবার সাবস্ক্রাইব করে। যদি Stream পরিবর্তিত হয় (উদাহরণস্বরূপ, প্যারেন্ট রিবিল্ডের সময়), StreamBuilder পুরানো স্ট্রিম থেকে আনসাবস্ক্রাইব করে এবং নতুনটিতে সাবস্ক্রাইব করে। এই আচরণ initialData এবং buildWhen প্যারামিটার দ্বারা নিয়ন্ত্রিত হয়, যা পুনর্নির্মাণের সংখ্যা অপ্টিমাইজ করার অনুমতি দেয়।
সারসংক্ষেপ: সাবস্ক্রিপশন জীবনচক্র বোঝা StreamBuilder-এর সঠিক ব্যবহারের ভিত্তি। ভুল স্ট্রিম ব্যবস্থাপনা মেমরি লিক বা UI-তে পুরানো ডেটার দিকে নিয়ে যায়।
AsyncSnapshot অবজেক্টের connectionState বৈশিষ্ট্য নির্ধারণ করে StreamBuilder স্ট্রিম প্রক্রিয়াকরণের কোন পর্যায়ে রয়েছে। চারটি অবস্থা আছে: none, waiting, active, done।
None হল প্রাথমিক অবস্থা যখন Stream এখনও ডেটা প্রেরণ শুরু করেনি। এই অবস্থায়, snapshot.connectionState ConnectionState.none-এর সমান এবং snapshot.data হল null। সাধারণত এই অবস্থায় একটি প্লেসহোল্ডার বা অপেক্ষা নির্দেশক দেখানো হয়। যদি Stream প্রাথমিক ডেটা সরবরাহ না করে, StreamBuilder এই অবস্থা থেকে শুরু করে।
Waiting হল অ্যাসিঙ্ক্রোনাস স্ট্রিম থেকে ডেটার অপেক্ষার অবস্থা। Stream সক্রিয়, কিন্তু ডেটা এখনও আসেনি। এই অবস্থা ঘটে, উদাহরণস্বরূপ, নেটওয়ার্ক থেকে ডেটা লোড করার সময় বা দীর্ঘস্থায়ী সংযোগ খোলার সময়। এই অবস্থায় CircularProgressIndicator বা কঙ্কাল লোডার দেখানো সাধারণ।
Active — স্ট্রিম ডেটা নির্গত করছে এবং UI বর্তমান তথ্য প্রদর্শন করছে। এই অবস্থায়, snapshot.hasData সত্য এবং snapshot.data-তে স্ট্রিমের সর্বশেষ মান থাকে। যদি স্ট্রিমটি Broadcast Stream হয়, সক্রিয় অবস্থা নতুন ডেটার অপেক্ষার সাথে সহাবস্থান করতে পারে।
Done — স্ট্রিম সম্পূর্ণ হয়েছে, কোনো নতুন ডেটা আসবে না। Snapshot.data-তে স্ট্রিম বন্ধ হওয়ার আগে প্রেরিত শেষ মান থাকে। যদি স্ট্রিম সফলভাবে সম্পূর্ণ হয়, snapshot.hasError মিথ্যা। এই অবস্থাটি চূড়ান্ত ফলাফল প্রদর্শনের জন্য ব্যবহৃত হয়: “লোডিং সম্পূর্ণ”-এর মতো বার্তা বা পরবর্তী স্ক্রিনে স্থানান্তর।
সারসংক্ষেপ: StreamBuilder-এর মাধ্যমে UI তৈরি করার সময়, চারটি অবস্থাই হ্যান্ডেল করা আবশ্যক যাতে ইন্টারফেস লোডিং, ডেটা, ত্রুটি এবং সমাপ্তি সঠিকভাবে প্রদর্শন করে।
StreamController dart:async প্যাকেজের একটি ক্লাস যা একটি Stream তৈরি এবং পরিচালনা করে। StreamController ডেটা যোগ করা, ত্রুটিগুলি হ্যান্ডেল করা এবং স্ট্রিম বন্ধ করা, এর জীবনচক্র নিয়ন্ত্রণ করার অনুমতি দেয়।
StreamController দুই ধরনের হয়: single-subscription (একজন সাবস্ক্রাইবার) এবং broadcast (একাধিক সাবস্ক্রাইবার)। Single-subscription কন্ট্রোলার একসাথে শুধুমাত্র একজন শ্রোতা গ্রহণ করে — দ্বিতীয় সাবস্ক্রিপশন একটি ব্যতিক্রম ছুঁড়বে। Broadcast কন্ট্রোলার একাধিক StreamBuilder-কে একসাথে একই স্ট্রিম শুনতে দেয়, যা BLoC এবং শেয়ার্ড অ্যাপ্লিকেশন অবস্থার জন্য দরকারী।
StreamController<T>.broadcast()-এর মাধ্যমে StreamController তৈরি করার সময়, প্রথম সাবস্ক্রিপশনের আগে যোগ করা ডেটা নতুন সাবস্ক্রাইবারদের জন্য পুনরায় চালানো হয় না। সংযোগের সময় সর্বশেষ মান পেতে, rxdart প্যাকেজের BehaviourSubject ব্যবহার করা হয়, যা শেষ ইভেন্ট ক্যাশে করে।
কন্ট্রোলারের সাথে কাজ শেষ করার পর, controller.close() কল করা আবশ্যক। close না কল করলে সম্পদ লিক হয়: স্ট্রিম খোলা থাকে, সাবস্ক্রাইবাররা মেমরিতে থাকে, এবং GC সম্পর্কিত অবজেক্ট মুক্ত করে না।
সারসংক্ষেপ: StreamController স্পষ্ট জীবনচক্র ব্যবস্থাপনার সাথে ব্যবহার করুন। Single-subscription স্ট্রিমের জন্য স্ট্যান্ডার্ড কন্ট্রোলার, শেয়ার্ড অবস্থার জন্য broadcast কন্ট্রোলার বা BehaviourSubject ব্যবহার করুন।
উদাহরণ 1 StreamController এবং StreamBuilder ব্যবহার করে একটি কাউন্টডাউন টাইমার প্রদর্শন করে।
import 'dart:async';
class TimerWidget extends StatefulWidget {
const TimerWidget({super.key});
final StreamController<int> controller = StreamController<int>();
void startTimer() {
int count = 0;
Timer.periodic(Duration(seconds: 1), (timer) {
controller.sink.add(count++);
if (count > 10) {
controller.close();
timer.cancel();
}
});
}
}
উদাহরণে, 1 সেকেন্ড ব্যবধানে 0 থেকে 10 পর্যন্ত সংখ্যা তৈরি করার জন্য একটি কন্ট্রোলার তৈরি করা হয়েছে। 10 এ পৌঁছানোর পর, close কল করা হয় এবং স্ট্রিম শেষ হয়। এই কন্ট্রোলারের স্ট্রিমে সাবস্ক্রাইব করা StreamBuilder প্রতিটি নতুন মান প্রদর্শন করবে।
উদাহরণ 2 — একাধিক উৎস থেকে ডেটা প্রদর্শনের জন্য Broadcast Stream-এর সাথে StreamBuilder-এর ব্যবহার।
final StreamController<String> broadcastController =
StreamController<String>.broadcast();
StreamBuilder<String>(
stream: broadcastController.stream,
initialData: 'Waiting for data...',
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Text('ত্রুটি: ${snapshot.error}');
}
return Text('ডেটা: ${snapshot.data}');
},
)
দ্বিতীয় উদাহরণটি সমস্ত অবস্থা হ্যান্ডেল করা দেখায়: প্রাথমিক প্রদর্শনের জন্য initialData, লোডিং নির্দেশকের জন্য waiting, ত্রুটির জন্য hasError, এবং সফল ফলাফলের জন্য data। এই প্যাটার্নটি StreamBuilder-এর সাথে প্রোডাকশন কোডের মানক।
সারসংক্ষেপ: প্রথম মুহূর্তে খালি স্ক্রিন এড়াতে initialData ব্যবহার করুন এবং ব্যবহারকারীকে ত্রুটি সঠিকভাবে দেখানোর জন্য সর্বদা hasError হ্যান্ডেল করুন।
ভুল 1: প্রতিটি প্যারেন্ট রিবিল্ডে নতুন Stream তৈরি করা। যদি Stream একটি এক্সপ্রেশনের মাধ্যমে পাস করা হয় যা প্রতিটি বিল্ডে নতুন অবজেক্ট তৈরি করে, StreamBuilder পুরানো থেকে আনসাবস্ক্রাইব করে এবং নতুন স্ট্রিমে সাবস্ক্রাইব করে, যা অসীম পুনর্নির্মাণ লুপের কারণ হয়। সমাধান: একটি remembered ভেরিয়েবল বা নির্দিষ্ট Stream-সহ StatefulWidget ব্যবহার করুন।
ভুল 2: ত্রুটি হ্যান্ডেলিংয়ের অভাব। একটি Stream controller.sink.addError-এর মাধ্যমে ত্রুটি নির্গত করতে পারে, এবং যদি builder snapshot.hasError পরীক্ষা না করে, ব্যবহারকারী খালি স্ক্রিন বা অসীম লোডিং দেখেন। সমাধান: সর্বদা hasError পরীক্ষা করুন এবং স্পষ্ট বার্তা দেখান।
ভুল 3: বন্ধ না করা StreamController-এর কারণে মেমরি লিক। যদি কন্ট্রোলার dispose-এ বন্ধ না করা হয়, স্ট্রিম বিদ্যমান থাকে এবং GC মেমরি মুক্ত করে না। সমাধান: dispose-এ controller.close() কল করুন এবং চূড়ান্ত কাজের জন্য done ইভেন্ট শুনুন।
ভুল 4: ধীর builder ফাংশনের সাথে StreamBuilder ব্যবহার করা। যেহেতু builder প্রতিটি স্ট্রিম ইভেন্টে কল করা হয়, এর ভিতরে ভারী গণনা ফ্রেম ড্রপের কারণ হয়। সমাধান: গণনাগুলি পৃথক isolate-এ সরান বা ডেটা রূপান্তরের জন্য Stream.map ব্যবহার করুন।
সারসংক্ষেপ: StreamBuilder একটি শক্তিশালী কিন্তু চাহিদাপূর্ণ হাতিয়ার। Stream জীবনচক্র পর্যবেক্ষণ করুন, ত্রুটিগুলি হ্যান্ডেল করুন এবং builder-এ ভারী অপারেশন এড়িয়ে চলুন।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
FutureBuilder একটি একক অ্যাসিঙ্ক্রোনাস ফলাফলের জন্য ডিজাইন করা হয়েছে: এটি একটি Future-এ সাবস্ক্রাইব করে, একটি মান পায় এবং শেষ হয়। StreamBuilder একটি Stream-এ সাবস্ক্রাইব করে, যা সময়ের সাথে একাধিক মান নির্গত করতে পারে, এবং প্রতিটি নতুন ইভেন্টে UI পুনর্নির্মাণ করে।
AsyncSnapshot একটি অপরিবর্তনীয় অবজেক্ট যা বর্তমান সাবস্ক্রিপশন অবস্থা (connectionState), শেষ প্রাপ্ত মান (data), এবং ত্রুটি অবজেক্ট (error) ধারণ করে যদি স্ট্রিম একটি ব্যতিক্রম নির্গত করে।
ত্রুটিগুলি builder ফাংশনে snapshot.hasError এবং snapshot.error বৈশিষ্ট্যের মাধ্যমে হ্যান্ডেল করা হয়। যদি স্ট্রিম sink.addError-এর মাধ্যমে ত্রুটি নির্গত করে, AsyncSnapshot ত্রুটিটি পায়, এবং builder-এর উপযুক্ত বার্তা বা ফলব্যাক UI দেখানো উচিত।
হ্যাঁ, যদি Stream broadcast হয় (StreamController.broadcast-এর মাধ্যমে তৈরি)। Single-subscription Stream শুধুমাত্র একজন সাবস্ক্রাইবারের অনুমতি দেয়। একাধিক উইজেটের মধ্যে একটি স্ট্রিম শেয়ার করতে, broadcast কন্ট্রোলার বা BehaviourSubject-সহ rxdart প্যাকেজ ব্যবহার করুন।
UI পুনর্নির্মাণ ট্রিগার করা ইভেন্টগুলি ফিল্টার করতে buildWhen প্যারামিটার ব্যবহার করুন। StreamBuilder-এ ডেটা পাঠানোর আগে ফিল্টার করতে Stream.transformer বা Stream.where প্রয়োগ করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন