چرخه حیات عناصر ListView در فلاتر

استفاده از ویجت لیست ویو (ListView) در فلاتر، برای نمایش آیتم های قابل اسکرول بسیار رایج است و اگر تجربه‌ی کار با فلاتر را دارید حتما با این ویجت آشنا هستید. آنچه در این مقاله خواهید خواند معرفی ویجت لیست ویو نیست. اگر اپلیکیشن های نسبتا بزرگی با فلاتر ایجاد کرده باشید به خوبی می دانید که لیست ویو یک ویجت مهم و تاثیر گذار در کارایی اپلیکیشن است. در ادامه مقاله، چرخه حیات لیست ویو و تاثیر آن در کارایی اپلیکیشن به همراه راه حل هایی برای بهبود کارایی را بررسی خواهیم کرد.

چرخه حیات عناصر لیست ویو

ایجاد: در حالی که لیست ویو در حال ترسیم (Draw) است، عناصر و استیت های فرزندان قابل مشاهده‌ی آن، بصورت lazy ایجاد خواهد شد (مثل وقتی از listView استفاده می شود) یا یک عنصر بصورت lazy فراهم می‌شود (مثل وقتی ListView.builder استفاده شده است).

تخریب: هر وقت فرزندی که از (ناحیه قابل مشاهده‌ی) اسکرول ویو خارج شود، عناصر و استیت های آن از درخت ویجت destroy می شوند. وقتی مجدد به همین قسمت اسکرول کنید، یک فرزند جدید مجددا بصورت lazy ایجاد خواهد شد؛ با عناصر و استیت جدید.

کنترل تخریب: برای اینکه استیت فرزندان را در هنگام اسکرول شدن به خارج از ناحیه قابل مشاهده حفظ کنید، چند روش پیشنهاد می شود:

  • منطقی که برای ساخت استیت ویو نیاز دارید را از زیردرخت فرزندان لیست خارج کنید. مثلا اگر یک لیست از پست ها با تعداد لایک های هر کدام دارید که از سرور دریافت می‌شوند، لیست پست ها و لایک های آنها را در یک مدل و خارج از لیست ویجت دریافت و ذخیره کنید. اجازه بدهید که ویوی زیردرخت فرزندان لیست، به راحتی از لیست مدلی که فراهم کردید، مجددا قابل ایجاد باشد. از StatefulWidget در زیردرخت ویجت فرزندان تنها برای ذخیره‌ی فوری استیت ui استفاده کنید.
  • زیردرخت ویجت فرزند (لیست) را که نیاز به حفظش دارید در ویجت KeepAlive قرار بدید. این ویجت، رندر آبجکتی که زیردرخت فرزند در آن قرار گرفته است را برای KeepAlive بودن علامت گذاری می‌کند. وقتی این رندر آبجکت (و طبیعتا ویجت داخل آن) از ناحیه دید خارج شود، لیست به جای اینکه رندر آبجکت فرزند (و عناصر و استیت های وابسته اش) را تخریب کند، آن در کش (cache) لیست ویو قرار می دهد و وقتی فرزند لیست دوباره به ناحیه دید برگشت، آن را همانطوری که در کش هست ترسیم می کند (البته اگر در این بین dirty نشده باشد. اگر با این مفهوم آشنا نیستید به این مقاله مراجعه کنید). این روش را فقط وقتی می‌توانید به کار ببرید که پارامترهای addAutomaticKeepAlives و addRepaintBoundaries لیست ویو مقدار false داشته باشند چون این پارامترها باعث می‌شوند که لیست ویو، هر زیردرخت ویجت فرزند خود را با ویجت های دیگری wrap کند. (در ادامه بیشتر با عملکرد این دو پارامتر آشنا می شویم.)
  • از ویجت های AutomaticKeepAlive (بصورت پیشفرض وقتی addAutomaticKeepAlives مقدار true دارد درج می شوند) استفاده کنید. AutomaticKeepAlive اجازه می‌دهد که ویجت های فرزند، کنترل کنند که آیا زیردرخت باید زنده نگه داشته شود یا نه. این رفتار در تضاد با KeepAlive است که بدون هیچ شرطی زیردرخت را زنده نگه می دارد (برای همین وقتی از KeepAlive استفاده می‌شود باید به این پارامتر مقدار false داد). به عنوان مثال ویجت EditableText وقتی فوکوس دارد، به زیردرخت لیست سیگنال زنده ماندن می‌دهد. اگر فوکوس نداشته باشد، وقتی زیردرخت فرزند از ناحیه دید اسکرول خارج شود تخریب می شود. فرزندان AutomaticKeepAlive معمولا با استفاده از AutomaticKeepAliveClientMixin سیگنال زنده ماندن می دهند. اینجا می توانید مثالی را ببینید که توضیح می دهد چطور می توانید ویجتی بنویسید که به همین روش سیگنال زنده ماندن بدهد.