RecyclerView با اسکرول روان در اندروید – راهنمای مقدماتی


RecyclerView یکی از پر تقاضاترین ویجتها در اندروید است و داشتن عملکرد اسکرول روان در نماهای پیچیده گاهی اوقات با مشکل مواجه میشود. اغلب دستگاهها با نرخ رفرش 60 فریم بر ثانیه کار میکنند. این بدان معنی است که حدوداً هر 16 میلیثانیه باید یک فریم جدید وجود داشته باشد. اگر اپلیکیشن شما بیش از 16 ثانیه زمان صرف محاسبه فریم بعدی برای نمایش بکند، کاربر یک فریم را از دست میدهد.
کش کردن قبلی نماها در Adapter
یکی از تنگناهایی که در زمان اسکرول کردن RecyclerView ممکن است رخ بدهد، ایجاد ViewHolder از طریق ()onCreateViewHolder است. زمانی که اسکرول میکنید، آداپتر یک ViewHolder بنا به تقاضا ایجاد میکند تا این که تعداد کافی از آنها برای بازیافت (Recycler) داشته باشد.
تولید نما (View) کُند است. اگر لیآوت XML پیچیده باشد، ممکن است بیش از 16 میلیثانیه صرف تولید نما شود و از این رو یک فریم از دست برود. اما اگر نماها را از قبل و پیش از نمایش دادن آنها به کاربر تولید بکنیم، چطور؟ این کار از طریق استفاده از withAsyncLayoutInflater برای تولید نماها روی نخ پسزمینه و دریافت یک callback در زمان آماده شدنشان میسر است.
در مثال زیر ما تنگناها را زمانی که Adapter ایجاد میشود، تولید میکنیم. در این وضعیت فرض میشود که تولید نما پیش از آن که دادهها به Adapter اضافه شوند، آغاز میشود. اگر دادهها پیش از ایجاد Adapter آماده نمایش باشند، در این صورت باید یک callback روی Adapter تنظیم کنیم تا زمانی که تولید همه نماها تکمیل شد به ما اطلاع دهد.
بهبود عملکرد اتصال نما
مورد دیگری که منجر به عملکرد کُند میشود، فراخوانی onBindViewHolder است. از آنجا که این متد عموماً برای هر ردیف درست پیش از وارد شدن به نما فراخوانی میشود، باید سریع باشد. اما گاهی اوقات در نماهای پیچیده ممکن است نیاز به محاسبات زیادی باشد، حتی فراخوانی setText() روی چند Textiew ممکن است برای تکمیل شدن به چندین میلیثانیه زمان نیاز داشته باشد.
این وضعیت را با ایجاد یک جدول زمانبندی کارهای UI میتوانیم بهبود بخشیم. در ViewHolder کد اتصال نما را به چند تابع تقسیم میکنیم که یکی برای تنظیم متن و یکی برای تنظیم تصویر است. میخواهیم مطمئن شویم که هر گام در مقدار زمان بسیار کمی اجرا میشود و کمتر از 8 میلیثانیه زمان میگیرد.
«جدول زمانبندی کار» (Job Scheduler) هر کار را به صورت پشت سر هم تحویل میدهد و میزان زمانی که طول میکشد را ثبت میکند. زمانی که به بیشینه زمان اختصاص یافته برای هر فریم نزدیک میشویم، این جدول صبر میکند تا فریم بعدی شروع شود و سپس به ادامه پردازش کارها میپردازد. بدین ترتیب UI فضایی برای نفس کشیدن پیدا میکند و فریم بعدی را رندر میکند. در عمل بهترین نتایج در زمان استفاده از بیشینه زمان 4 میلیثانیه برای هر فریم به دست میآید که بسیار کمتر از 16 میلیثانیه زمان موجود برای هر فریم است. اما میتوانید این عدد را روی مقادیر مختلف تنظیم کنید تا نتایج را دقیقتر بررسی کنید.
کاربرد آن آسان است:
مشکلات احتمالی
کلاس UIJobScheduler برای ادامه اتصال نما ممکن است به یک یا دو فریم اضافی نیاز داشته باشد که معنی آن این است نما میتواند دادههای قدیمی را پیش از بهروزرسانی نمایش دهد. ما در زمان تست مشکلی با این مسئله نداشتیم، اما به هر حال احتمال بروز مشکل وجود دارد.
سخن پایانی
()onCreateViewHolder و ()onBindViewHolder دو متدی هستند که آداپتر RecyclerView ممکن است کند شود و موجب تأخیر در اسکرول شود. عملکرد onCreateViewHolder را میتوان با کش کردن قبلی نماها بهبود بخشید. همچنین عملکرد onBindViewHolder را میتوان با پخش کارها روی فریمهای مختلف از طریق سینگلتون UIJobScheduler بهبود داد.
فیسبوک یک کتابخانه اختصاصی به نام Litho (+) برای بهبود عملکرد اسکرول خود توسعه داده است. این کتابخانه از پارادایم متفاوتی استفاده میکند که نیازمند ریفکتور کردن کد موجود اندروید است، اما عملکرد آن بسیار خوب به نظرمی رسد.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی اندروید
- گنجینه برنامه نویسی اندروید (Android)
- مجموعه آموزشهای برنامهنویسی
- ساخت کتابخانه اندروید و انتشار آن — به زبان ساده
- نوتیفیکیشن اندروید — اصول مقدماتی
==