BuildContext হল Flutter-এর একটি মৌলিক অবজেক্ট যা এলিমেন্ট ট্রিতে একটি নির্দিষ্ট উইজেটের অবস্থান উপস্থাপন করে এবং তার পরিবেশে অ্যাক্সেস প্রদান করে। অফিসিয়াল Flutter ডকুমেন্টেশন (Flutter.dev, 2026) অনুসারে, BuildContext উইজেট এবং ফ্রেমওয়ার্কের মধ্যে একটি সেতু হিসেবে কাজ করে: এর মাধ্যমে উইজেট থিম (Theme), মিডিয়া কুয়েরি (MediaQuery), স্থানীয়করণ (Localizations) এবং InheritedWidget থেকে ডেটা গ্রহণ করে। প্রতিটি উইজেটের নিজস্ব BuildContext থাকে, যা build মেথডে প্রথম আর্গুমেন্ট হিসেবে পাস করা হয়।
মূল বিষয়
BuildContext হল একটি ইন্টারফেস যা Element ক্লাস দ্বারা বাস্তবায়িত হয় এবং উইজেটকে UI শ্রেণিবিন্যাসে তার অবস্থান সম্পর্কে তথ্য প্রদান করে। BuildContext-এর প্রতিটি ইনস্ট্যান্স ট্রিতে একটি নির্দিষ্ট অবস্থানের জন্য অনন্য এবং অন্য কোনো স্থানে সরানো যায় না। যদি কোনো উইজেট তার প্যারেন্ট পরিবর্তন করে (উদাহরণস্বরূপ, অন্য কন্টেইনারে চলে যায়), তাহলে এটি একটি নতুন BuildContext পায়।
BuildContext-এর প্রধান উদ্দেশ্য হল InheritedWidget-এ অ্যাক্সেস প্রদান করা। কনটেক্সটের মাধ্যমে, উইজেট ট্রিতে উপরের দিকে গিয়ে নিকটতম Theme, MediaQuery, Navigator বা Directionality ইনস্ট্যান্স খুঁজে পায়। এই প্রক্রিয়াটি Flutter-এ থিম, নেভিগেশন এবং অভিযোজিত লেআউটের পুরো সিস্টেমের ভিত্তি। BuildContext ছাড়া কোনো উইজেট এই ডেটা অ্যাক্সেস করতে পারে না।
Flutter আর্কিটেকচারাল ডক্স (Google, 2026) অনুসারে, BuildContext আকার মাপা এবং অবস্থান নির্ধারণের জন্য উইজেটের সাথে যুক্ত RenderObject খুঁজতেও ব্যবহৃত হয়। findRenderObject() এবং size-এর মতো মেথডগুলি কনটেক্সটের মাধ্যমে উপলব্ধ। কনটেক্সট Localizations.of(context)-এর মাধ্যমে স্থানীয়করণেও অ্যাক্সেস প্রদান করে।
একটি গুরুত্বপূর্ণ আর্কিটেকচারাল বোধগম্যতা: BuildContext হল একটি ইন্টারফেস যা Element বাস্তবায়ন করে, Widget নয়। Element হল Widget (কনফিগারেশন) এবং RenderObject (প্রকৃত প্রদর্শন)-এর মধ্যে “আঠা”। যখন ডকুমেন্টেশন “উইজেট কনটেক্সট” বলে, তখন এটি সেই এলিমেন্টকে বোঝায় যা সেই উইজেটটি পরিচালনা করে। build মেথড ঠিক এই ধরনের কনটেক্সট পায় — তৈরি করা হচ্ছে এমন উইজেটের কনটেক্সট, এটি যে চাইল্ড উইজেটগুলি ফেরত দেয় তার নয়।
BuildContext-এর কাজের প্রক্রিয়া এলিমেন্ট ট্রি নিচ থেকে উপরে ট্রাভার্স করার উপর ভিত্তি করে। যখন কোনো উইজেট Theme.of(context) কল করে, তখন কনটেক্সট বর্তমান এলিমেন্ট থেকে খোঁজ শুরু করে এবং মূলের দিকে উপরের দিকে অগ্রসর হয়, প্রতিটি এলিমেন্টকে Theme টাইপের InheritedWidget-এর জন্য পরীক্ষা করে। পাওয়া প্রথম InheritedWidget ফেরত দেওয়া হয় — এটি নিশ্চিত করে যে উইজেট নিকটতম সংজ্ঞা থেকে থিম পায়।
প্রতিটি BuildContext প্যারেন্ট কনটেক্সট (parent) এবং চাইল্ড কনটেক্সটগুলির রেফারেন্স সংরক্ষণ করে। এটি একটি দ্বিমুখী সংযোগ যা ট্রিতে উপরের দিকে (প্যারেন্টদের কাছে) এবং নিচের দিকে (শিশুদের কাছে) উভয় দিকে ট্রাভার্সালের অনুমতি দেয়। Flutter-এ InheritedWidget খোঁজার জন্য শুধু উপরের দিকে ট্রাভার্সাল ব্যবহার করা হয় — একটি উইজেট শুধু পূর্বপুরুষদের থেকে ডেটা পেতে পারে, বংশধরদের থেকে নয়। এটি একটি মৌলিক আর্কিটেকচারাল সীমাবদ্ধতা।
Flutter সোর্স কোড (Flutter SDK, 2026) অনুসারে, BuildContext-এ মেথড রয়েছে: visitAncestorElements, visitChildElements, findAncestorWidgetOfExactType, dependOnInheritedWidgetOfExactType এবং getRenderObject। শেষ দুটি সবচেয়ে বেশি ব্যবহৃত: dependOnInheritedWidgetOfExactType শুধু InheritedWidget খুঁজে পায় না বরং তার পরিবর্তনগুলিতে সাবস্ক্রাইবও করে (যখন InheritedWidget পরিবর্তিত হয়, উইজেট পুনর্নির্মিত হয়)।
dependOnInheritedWidgetOfExactType হল BuildContext-এর মূল মেথড যা প্রতিক্রিয়াশীলতা প্রদান করে। যখন কোনো উইজেট Theme.of(context) কল করে, এটি শুধু থিম পায় না — এটি তার পরিবর্তনগুলিতেও সাবস্ক্রাইব করে। যদি Theme পরিবর্তিত হয় (উদাহরণস্বরূপ, ডার্ক/লাইট মোড সুইচ করার সময়), সমস্ত সাবস্ক্রাইবড উইজেট স্বয়ংক্রিয়ভাবে পুনর্নির্মিত হয়। এটি Flutter-এ প্রতিক্রিয়াশীলতার প্রক্রিয়া।
BuildContext হল একটি ইন্টারফেস, যেখানে Element হল তার বাস্তবায়ন। Flutter কোডে, আপনি সবসময় BuildContext ইন্টারফেসের মাধ্যমে কাজ করেন নির্দিষ্ট এলিমেন্ট টাইপ (StatelessElement, StatefulElement, ProxyElement, ইত্যাদি) না জেনে। এটি ইচ্ছাকৃত: ডেভেলপারকে এলিমেন্টের বাস্তবায়নের বিবরণ জানার প্রয়োজন নেই — পরিবেশে অ্যাক্সেসের জন্য ইন্টারফেস যথেষ্ট।
বিভিন্ন এলিমেন্ট টাইপ BuildContext কে বিভিন্নভাবে বাস্তবায়ন করে: StatelessElement কেবল build কল পাস করে, StatefulElement State পরিচালনা করে, এবং InheritedElement dependOnInheritedWidgetOfExactType-এর মাধ্যমে সাবস্ক্রিপশন ট্র্যাক করে। তবে ডেভেলপারের দৃষ্টিকোণ থেকে, এগুলি সবই একটি সমন্বিত API সহ BuildContext।
| দিক | BuildContext | Element |
|---|---|---|
| টাইপ | ইন্টারফেস (অ্যাবস্ট্র্যাক্ট ক্লাস) | বাস্তবায়ন ক্লাস |
| ব্যবহার | ডেভেলপার build-এ ব্যবহার করে | Flutter অভ্যন্তরীণ প্রক্রিয়া |
| খোঁজার মেথড | of(), findAncestor...() | mount, update, unmount |
| সর্বজনীনতা | সর্বজনীন API | প্যাকেজ-অভ্যন্তরীণ |
| উইজেটের সাথে সম্পর্ক | widget ফিল্ডের মাধ্যমে | widget এবং state-এর মালিক |
থিম এবং মিডিয়া কুয়েরি অ্যাক্সেসের জন্য BuildContext-এর মৌলিক ব্যবহার:
class ThemedText extends StatelessWidget {
const ThemedText({super.key});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final media = MediaQuery.of(context);
return Container(
padding: EdgeInsets.all(media.size.width * 0.02),
child: Text(
'স্টাইল করা টেক্সট',
style: theme.textTheme.headlineMedium,
),
);
}
}
BuildContext-এর মাধ্যমে নেভিগেশনের উদাহরণ। Navigator.of(context) ট্রিতে উপরের দিকে নিকটতম Navigator খোঁজার জন্য কনটেক্সট ব্যবহার করে:
class _NavigateButtonState extends State<NavigateButton> {
void _navigate() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const DetailsScreen(),
),
);
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _navigate,
child: const Text('বিবরণে যান'),
);
}
}
BuildContext-এর মাধ্যমে উইজেটের আকার খোঁজার উদাহরণ। findRenderObject() মেথড একটি RenderObject ফেরত দেয় যা থেকে আকার পাওয়া যায়:
void _printSize(BuildContext context) {
final renderBox = context.findRenderObject() as RenderBox?;
if (renderBox != null) {
print('উইজেটের আকার: ${renderBox.size}');
}
}
গুরুত্বপূর্ণ: findRenderObject() null ফেরত দেয় যদি উইজেটটি এখনও মাউন্ট না করা হয় বা ইতিমধ্যে আনমাউন্ট করা হয়ে থাকে। ব্যবহারের আগে সবসময় null-এর জন্য ফলাফল পরীক্ষা করুন। build-এর ভিতরে নির্মাণ সম্পূর্ণ হওয়ার আগে এই মেথড কল করলেও null ফিরতে পারে।
InheritedWidget হল একটি বিশেষ উইজেট যা BuildContext-এর মাধ্যমে ট্রিতে নিচের দিকে দক্ষতার সাথে ডেটা প্রচার করে। যখন কোনো চাইল্ড উইজেট MyInheritedWidget.of(context) কল করে, BuildContext ট্রিতে উপরের দিকে যায়, মিলে যাওয়া টাইপের নিকটতম InheritedWidget খুঁজে এবং তার ডেটা ফেরত দেয়। একই সময়ে, কনটেক্সট পরিবর্তনগুলিতে সাবস্ক্রাইব করে: যদি InheritedWidget পরিবর্তিত হয়, সমস্ত সাবস্ক্রাইবড উইজেট স্বয়ংক্রিয়ভাবে পুনর্নির্মিত হয়।
BuildContext + InheritedWidget-এর সমন্বয় গ্লোবাল ভেরিয়েবল এবং প্রপ ড্রিলিং (কনস্ট্রাক্টরের চেইনের মাধ্যমে ডেটা পাস করা) প্রতিস্থাপন করে। ১০ স্তরের উইজেটের মাধ্যমে থিম পাস করার পরিবর্তে, প্রতিটি উইজেট Theme.of(context)-এর মাধ্যমে সরাসরি এটি অ্যাক্সেস করতে পারে। এটি কোডকে পরিষ্কার করে এবং পাস করা প্যারামিটারের সংখ্যা হ্রাস করে।
Flutter টিম (Google, এপ্রিল 2026) অনুসারে, InheritedWidget এতটাই কার্যকরী একটি প্রক্রিয়া যে সমস্ত অফিসিয়াল স্টেট ম্যানেজমেন্ট সমাধান এটির উপর নির্মিত: Provider InheritedWidget-কে মোড়ায়, Riverpod এটিকে তার একটি স্তর হিসেবে ব্যবহার করে, এবং Flutter SDK নিজে (Theme, MediaQuery, Navigator, Localizations) সম্পূর্ণভাবে এই আর্কিটেকচারের উপর ভিত্তি করে।
নিজের InheritedWidget তৈরি করা বাহ্যিক নির্ভরতা ছাড়াই ডেটা প্রচারের অনুমতি দেয়। ক্লাসটি InheritedWidget-কে প্রসারিত করে এবং একটি স্ট্যাটিক of(BuildContext context) মেথড প্রদান করে। এটি সহজ পরিস্থিতির জন্য Provider-এর একটি ন্যূনতম বিকল্প:
class AppConfig extends InheritedWidget {
final String apiUrl;
final bool useDarkMode;
const AppConfig({
super.key,
required this.apiUrl,
required this.useDarkMode,
required super.child,
});
static AppConfig of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<AppConfig>()!;
}
@override
bool updateShouldNotify(AppConfig oldWidget) {
return apiUrl != oldWidget.apiUrl || useDarkMode != oldWidget.useDarkMode;
}
}
এখন ট্রিতে নিচের দিকে যে কোনো উইজেট কনফিগারেশন অ্যাক্সেস করতে পারে: final config = AppConfig.of(context);। যদি কনফিগারেশন পরিবর্তিত হয়, সমস্ত সাবস্ক্রাইবড উইজেট স্বয়ংক্রিয়ভাবে পুনর্নির্মিত হবে।
প্রথম সাধারণ ভুল হল dispose-এর পরে BuildContext সংরক্ষণ করা বা mounted চেক না করে অ্যাসিঙ্ক্রোনাস কলব্যাকে এটি ব্যবহার করা। BuildContext একটি এলিমেন্টের সাথে আবদ্ধ, এবং এলিমেন্টটি ধ্বংস হতে পারে (যখন উইজেট ট্রি থেকে সরানো হয়)। এলিমেন্ট ধ্বংস হওয়ার পরে কনটেক্সট ব্যবহার করলে ব্যতিক্রম হয়। সমাধান হল context.mounted (নতুন Flutter সংস্করণে উপলব্ধ) ব্যবহার করা বা State-এ mounted চেক করা।
দ্বিতীয় ভুল হল initState-এ Theme.of(context) কল করা। initState পর্যায়ে, কনটেক্সট এখনও ট্রিতে সম্পূর্ণভাবে মাউন্ট হয়নি। initState-এ InheritedWidget খোঁজা null ফেরত দিতে পারে বা ব্যতিক্রম ছুঁড়তে পারে। সমস্ত of(context) কল build বা didChangeDependencies-এ করা উচিত, যেখানে কনটেক্সট ট্রিতে থাকার নিশ্চয়তা রয়েছে।
তৃতীয় ভুল হল একটি উইজেটের BuildContext ব্যবহার করে অন্য উইজেটে হেরফের করা। BuildContext প্যারেন্ট-চাইল্ড শ্রেণিবিন্যাসের বাইরে ক্রস-উইজেট মিথস্ক্রিয়ার জন্য ডিজাইন করা হয়নি। যদি আপনার অন্য উইজেটের অবস্থা পরিচালনার প্রয়োজন হয়, কলব্যাক, কন্ট্রোলার বা স্টেট ম্যানেজমেন্ট টুল ব্যবহার করুন।
চতুর্থ ভুল হল BuildContext-কে একটি অ্যাসিঙ্ক্রোনাস ফাংশনে পাস করা যা উইজেটের dispose-এর চেয়ে বেশি দিন বেঁচে থাকে। একটি সাধারণ পরিস্থিতি: Navigator.of(context) একটি ভেরিয়েবলে সংরক্ষিত এবং ব্যবহারকারী স্ক্রিন ছেড়ে যাওয়ার পরে ব্যবহার করা হয়। সমাধান হল স্ট্যাটিক বা দীর্ঘস্থায়ী অবজেক্টে কনটেক্সট সংরক্ষণ না করা।
অ্যাসিঙ্ক্রোনাস অপারেশনে BuildContext-এর সাথে কাজ করার জন্য একটি নিরাপত্তা প্যাটার্ন: কনটেক্সট ব্যবহারের আগে সবসময় mounted চেক করুন এবং উইজেটের চেয়ে বেশি দিন বাঁচতে পারে এমন ক্লোজারে কনটেক্সট সংরক্ষণ করবেন না:
Future<void> _safeNavigation(BuildContext context) async {
await Future.delayed(const Duration(seconds: 2));
if (!context.mounted) return;
Navigator.of(context).push(MaterialPageRoute(...));
}
BuildContext-এর সাথে কাজ করার জন্য এর জীবনচক্র এবং সীমাবদ্ধতা বোঝা প্রয়োজন। প্রথম নিয়ম: শুধুমাত্র সেই মেথডগুলির ভিতরে কনটেক্সট ব্যবহার করুন যা এটি প্যারামিটার হিসাবে পায় (build, didChangeDependencies)। ক্লাস ফিল্ড বা স্ট্যাটিক ভেরিয়েবলে কনটেক্সট সংরক্ষণ করবেন না — এটি প্রায় সবসময় বাগের দিকে নিয়ে যায়।
দ্বিতীয় নিয়ম: InheritedWidget থেকে ডেটা অ্যাক্সেসের জন্য build-এর পরিবর্তে didChangeDependencies পছন্দ করুন। যদি ডেটা শুধুমাত্র প্রাথমিককরণের জন্য প্রয়োজন হয় রেন্ডারিংয়ের জন্য নয়, didChangeDependencies সঠিক স্থান। এটি UI নির্মাণ থেকে প্রাথমিককরণ যুক্তি আলাদা করতে দেয় এবং প্রতিটি আপডেটে পুনরাবৃত্ত কল এড়ায়।
তৃতীয় নিয়ম: অ্যাসিঙ্ক্রোনাস অপারেশনের সাথে কাজ করার সময়, এমন কলব্যাক ব্যবহার করুন যা কনটেক্সটের উপর নির্ভরশীল নয়, বা mounted চেক করুন। যদি কোনো অ্যাসিঙ্ক্রোনাস অপারেশনে নেভিগেশন বা থিম অ্যাক্সেসের প্রয়োজন হয়, এই ডেটা আগে থেকে পান (সিঙ্ক্রোনাস build বা initState কনটেক্সটে) এবং এটি কনটেক্সটে নয়, লোকাল ভেরিয়েবলে সংরক্ষণ করুন।
সচরাচর জিজ্ঞাসা
BuildContext হল একটি ইন্টারফেস যা এলিমেন্ট ট্রিতে উইজেটের অবস্থান উপস্থাপন করে। এর মাধ্যমে, উইজেট তার পরিবেশে অ্যাক্সেস পায়: থিম, মিডিয়া কুয়েরি, নেভিগেটর এবং InheritedWidget থেকে ডেটা। প্রতিটি উইজেটের নিজস্ব অনন্য কনটেক্সট রয়েছে।
BuildContext বর্তমান এলিমেন্ট থেকে উপরে মূলের দিকে ট্রি ট্রাভার্স করে, অনুরোধকৃত টাইপের নিকটতম InheritedWidget খুঁজে পায়। dependOnInheritedWidgetOfExactType মেথড শুধু ডেটা খুঁজে পায় না বরং উইজেটকে পরিবর্তনে সাবস্ক্রাইবও করে — যখন InheritedWidget আপডেট হয়, উইজেট স্বয়ংক্রিয়ভাবে পুনর্নির্মিত হয়।
BuildContext ট্রিতে একটি এলিমেন্টের সাথে আবদ্ধ, এবং এলিমেন্টটি ধ্বংস হতে পারে (উইজেট সরানো হয়)। উইজেট সরানোর পরে সংরক্ষিত কনটেক্সট ব্যবহার করলে ব্যতিক্রম হয়। যদি অ্যাসিঙ্ক্রোনাস কলব্যাকে কনটেক্সটের প্রয়োজন হয়, ব্যবহারের আগে mounted চেক করুন।
BuildContext হল একটি ইন্টারফেস, Element হল তার বাস্তবায়ন। ডেভেলপার নির্দিষ্ট এলিমেন্ট টাইপ না জেনে BuildContext-এর মাধ্যমে কাজ করে। Element হল Flutter-এর অভ্যন্তরীণ প্রক্রিয়া যা Widget-কে RenderObject-এর সাথে সংযুক্ত করে এবং জীবনচক্র পরিচালনা করে।
অন্য উইজেটের কনটেক্সটে সরাসরি অ্যাক্সেস নেই। প্যারেন্ট কনটেক্সটের জন্য State-এর জন্য context.findAncestorStateOfType বা কী (GlobalKey) ব্যবহার করুন। চাইল্ড-এর জন্য — একটি কলব্যাক পাস করুন। BuildContext শ্রেণিবিন্যাসের বাইরে ক্রস-উইজেট অ্যাক্সেসের জন্য ডিজাইন করা হয়নি।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন