بعد از اینکه یه سری دورههای آموزشی ایرانی رو دیدم و ( حتی انگلیسی ) مبحثی که کمتر بهش توجه شده بود چرخه حیاط برنامه توی فریمورک فلاتره. چرخه حیاط ( lifecycle ) به روند اجرای یک برنامه توی حافظه رم گفته میشه. حالا این برنامه میتونه با پایتون باشه و یه عملیات رو انجام بده و تموم بشه، یه برنامه هم میتونه بره توی background و تا زمانی که گوشی کار میکنه فعال باشه.
این داستان چرخه حیاط زمانی شروع میشه که شما یه اپ رو داری مینویسی یه سری عملیاتهایی رو داری و ممکن بعضی از اونها مدتها زمان بخوان برای اجرا شدن ( مثلا یه listener توی اپ که state نتورک گوشی رو هندل میکنه ).
برنامه باید به صورتی باشه که listener من زمانی که برنامه میره توی حالت deactive یا به اصطلاح میره توی حافظه موقت تا کاربر دوباره وارد اون بشه، اون listener هم یه استوپی داشته باشه تا زمانی که دوباره اپ بیاد تو حالت اکتیو. حالا اگه این اتفاق نیفته چی؟؟
فرض کنید که این listener هر زمانی که اینترنت وصل شد یه عملیاتی رو انجام بده و اون رو بریزه توی دیتابیس، توی این زمان کاربر ممکنه state نتورک خودش رو عوض کنه مثلا یهو اینترنتش تموم بشه یا به وایفای وصل بشه، در این صورت کاری که برنامه انجام میده اینه که میره request میزنه به سرور و عملیاتها رو انجام میده و نیاز داره تا اپ توی حافظه نگه داری بشه، زمانی که شما این کار رو انجام دادید یه مشکلی به وجود میاد، memoryleack.
مثال من، مثال درستی نبود و فقط برای اینه که متوجه داستان باشید گفته شده.
بعد از این مشکل اپ شما فریز میشه، هنگ میکنه، متوقف میشه و هزاران اتفاق دیگه که نباید بیفته چون اگه از سرویس نتیفیکیشن استفاده کنید دیگه نمیتونید اون رو دریافت کنید.
برخی موارد هم هست که فرایند شما اونقدری سنگین میشه که شروع میکنه به خوردن گوشی کاربر میکنه و گوشی داغ میکنه، کند میشه و ...
پس همیشه باید به lifecycle توجه کرد که اتفاقات ناخواستهای برای برنامه شما نیفته. اما حالا اینهمه حرف برای چی بود؟ درسته flutter هم مثل باقی برنامهها و فریمورکها یه lifecycle داره برای screen هایی که توی برنامه اجرا میشن. ( توی فلاتر activity ها با عنوان screen شناخته میشن )
اگه با فلاتر کار کرده باشید با انواع مختلف widget های screen آشنا هستید.
StatelessWidget, StatefulWidget
این دو نوع ویجت شاکله اصلی تمامی screenهای موجود هستن و برای خودشون یه چرخه حیاط توی برنامه نیتیو و یکی هم توی خود فلاتر دارن.
چرخه حیاط نیتیو همون چرخهی بیسیکی هست که برنامه های سیستمهای عامل دارن. مثلا برای اندروید به این صورته:onCreate, , , , , onDestroy.
خوب حالا بریم سراغ برسی چرخه حیاط با استفاده از این توابع
توی زمانیکه شما از StatelessWidget استفاده میکنید، صفحه شما توی تابع onCreate ساخته میشه و screen شما توسط engain فلاتر توی اکتیویتی به نمایش درمیاد و بعد از اینکه برنامه متود onDestroy رو صدا زد برنامه کلا تموم میشه.
اینو بگم که برنامه شما توی فلاتر در حالت پیشفرض توی یک اکتیویتی اجرا میشن و بقیه کارها توی flutter engain انجام میشه.
خوب حالا نوبت اونه که با StatefulWidget آشنا بشم و بفهمیم که چطور کار میکنه.
توی این ویجت lifecycle از چند مرحله تشکیل شده که میتونه به شما کمک کنه متوجه بشید که توی مراحل مختلف screen داره چه اتفاقی میفته.
معمولا Stateless ویجتها screen های یکتایی هستند که تغییری توی اونها اعمال نمیشه و اگر بخواید به صورت realtime یک مقدار رو تغییر بدید و این تغییر رو روی صفحه نمایش بدید این امکان براتون وجود نداره، برعکس اون توی StateufulWidget شما میتونید این کار با استفاده از متود setState انجام بدید و تغییرات جدید رو به کاربر نمایش بدید.
تو این نوع ویجت lifecycle به این شکل اتفاق میافته:
createState:
تمامی StateFulWidget ها از دو تا کلاس تشکیل شدن.
خوب کلاس MyHomePage رو به عنوان کلاس Widget میشناسیم. این کلاس سازنده یا مادر State ماست. تمامی property هایی که قراره به این screen یا این Widget پاس داده بشه میره و توی کلاس Widget میشینه و متود createState به عنوان اولین گام چرخه حیاط برنامه state صفحه رو برای نمایش به activity ما پاس میده.
کلاس دوم هم، کلاس State نامیده میشه که معمولا با این الگو نام گذاری میشه:
_{WidgetClassName}State
دیگه باقی کارها رو باید توی این کلاس انجام بدید و کدهایی که قراره نتیجه اون به کاربر نمایش داده بشه توی این قسمت گذاشته میشن.
initState():
این متود اولین چیزیه که بعد از ساخته شدن و به نمایش دراومدن کلاس state فراخونده میشه ( یعنی بعد از متود سازنده، این متود اجرا میشه ).
didChangeDependencies():
توضیح این متود یکم کار سخته اما به صورت کلی باید بهتون بگم که بعد از متود initState این متود اجرا میشه و اگه یه InheritedClass کلاس داشته باشه، با استفاده از این متود به تغییرات state برنامه گوش میکنه و با به InheritedClass کلاس ما میگه که خوب state تغییر کرده و شما هم باید خودت رو تغییر بدی . کمتر کسی از این متود استفاده میکنه مگه اینکه بخواید کار خیلی عجیب غریبی انجام بدید. ( پس خیلی خودتون رو درگیر این یکی نکنید ?? )
didUpdateWidget():
خوب بیاید این متود رو بهتون معرفی میکنم.( بچهها didUpdateWidget، didUpdateWidget بچه ها ? )
این متود چه کاری انجام میده؟ زمانی که شما این widget رو توی یک subtree از screen ها قرار بدید، ممکنه که screen مادر تغییراتی داشته باشه که نیاز باشه همگام با اون تغییرات این widget, state هم تغییر کنن. این متود میاد چک میکنه اگه مادر تغییر کرد من نیاز دارم تغییر کنم یا نه که به صورت پیشفرض همیشه تغییر میکنه و نیازی نیست خیلی از این متود استفاده کنید.
این متود همیشه بعد از didChangeDependencies و قبل از build اجرا میشه.
build():
شاید بشه گفت اصلی ترین متودی که باید از اون توی state های فلاتر استفاده کنید این ویجت باشه. بعد از دو مرحله ای که در بالا براتون توضیح دادم نوبت به اون میشه که کدهای ui رو که نویشتیم و قراره به کاربران نمایش بدیم رندر بشه و به نمایش دربیاد.
بله درست متوجه شدید!! این متود کارش دقیقا همینه و یک سری اتفاقاتی هم براش میفته که توی ادامه به اونها اشاره خواهیم کرد.
setState():
نوبتی هم که باشه، نوبت این تابع گرانبها و عزیزه. زمانیکه شما مقادیری رو توی state خودتون تغییر بدید و نیاز داشته باشید که اون مقدار در صفحه هم تغییر کنه باید از این متود استفاده کنید. ( مثلا بیشتر یا کمتر کردن یک عدد )
این متود یک فانکشن میگیره که به صورت synchronous انجام میشه و نمیتونیم از async/await برای اون استفاده کنیم.
زمانی که شما این تابع رو فراخوانی کنید همه چیز آماده میشه تا دوباره متود build ساخته بشه و به اصطلاح صفحه rerender بشه.
deactivate():
این متود به ندرت استفاده میشه و زمانی که screen از subtreeحذف توسط flutter فراخونده میشه و screen رو میبره تو حالت اغماااااا. ??
اما این متود یکسری توضیحات داره که ترجیح میدم توی متود بعدی براتون بنویسمش پس یکم بیاید پایینتر.
dispose():
خوب این متود کارش تقریبا شبیه به متود قبلیه اما با یکم توضیح و تفاوت. اول بگم که این متود هم وقتی flutter بخواد screen رو حذف کنه بعد از deactivate اجرا میشه. اما تفاوت؟؟
خوب بعضی وقتا هست که شما برای screen خودتون یک listener ساختید و این listener داره کار میکنه و هنوز از کار نیفتاده، flutter به جای اینکه از dispose برای نابود کردن screen استفاده کنه میاد و از deactivate استفاده میکنه تا بتونه فرصتی بده به اون listener تا به کار خودش پایان بده و بعد از اون بیاد و این متود رو اجرا کنه.
خوب دیگه فکر میکنم که همه متودهای این widget رو هم براتون گفته باشم.
امیدوارم که تونسته باشم کمکتون کرده باشم و سعی میکنم درباره فلاتر و بعد از اون هم جنگو بیشتر براتون بنویسم. خوشحال میشم که نظر بدید تا بهتر بتونیم این مقالات رو بنویسم. :)
ممنون که وقت گذاشتی دوست من ?