RecyclerView چیست؟
اگر بخواهید لیستی از آیتمها که تعدادشان خیلی زیاد است و یا محتوای آنها معمولا تغییر میکند را در نرمافرتان نشان دهید، باید از RecyclerView استفاده کنید. RecyclerView، نسخهی پیشرفتهتر و منعطفتری از ListView محسوب میشود.
روند کاری RecyclerView
چرخهی کاری Recyclerview (ساده شده) به شکل زیر میباشد:
یک RecyclerView، خود را با viewهایی که یک layout manager فراهم میکند پُر میکند. این وظیفهی شماست که layout manager مناسب و مد نظر خودتان را برای RecycleView فراهم کنید، برای اینکار میتوانید از یکی از layout manager های استاندارد (مثل LinearLayoutManager یا GridLayoutManager)، یا پیادهسازی خودتان استفاده کنید.
آیتمهای موجود در لیست، توسط شیء view holder نمایش داده میشوند.این اشیاء نمونههایی از کلاسی هستند که شما با extend کردنِ آن از RecyclerView.ViewHolder میسازید.
هر view holder، وظیفهی نمایش یک آیتم در صفحه را بر عهده دارد. برای مثال، اگر لیست شما قرار است دستهبندی موزیکها را نمایش دهد، هر view holder میتواند یک آلبوم را نمایش دهد.
Recycleview فقط به تعداد مورد نیازی از view holder را که برای نمایش در صفحه لازم است بعلاوهی چند تا به صورت یدکی تولید میکند. وقتی کاربر لیست را اسکرول میکند، RecyclerView به صورت خودکار viewهایی که از صفحه خارج شدهاند را برداشته و با مقادیر جدید که وارد صفحه میشوند اصطلاحا rebindمیکند.
اشیاء view holder توسط یک آداپتور (adapter) که شما با نوشتنِ کلاسی که از RecyclerView.Adapter ارثبری میکند میسازید مدیریت میشوند. این آداپتور، در زمان نیاز، view holder را تولید میکند. بعلاوه این آداپتور view holder ها را به دادههای متناظر خودشان نسبت میدهد (داده ها را برایشان ست میکند).
آداپتور این کار را با نسبت دادن view holder به یک مکان عددی (position) و فراخوانی تابع onBindViewHolder() آداپتور انجام میدهد. این تابع از مکان view holder برای تشخیص اینکه چه دادههایی باید برایش ست شود استفاده میکند.
به صورت خلاصه، جریان فعالیت RecyclerView به شکل زیر میباشد:
RecyclerView: همه چیز را مدیریت میکند. اکثر بخشهای آن از قبل در اندروید نوشته شده است. شما اجزا و تنظیمات مورد نیاز را برایش فراهم میکنید.
Adapter: بیشتر زمان شما صرف کد زدن در این کلاس میشود. این کلاس به دیتاسورس شما متصل میشود. وقتی با RecyclerView استفاده شود، ساخت و یا آپدیت آیتمهای مجزای موجود در لیست را انجام میدهد.
ViewHolder: یک کلاس ساده که داده را به آیتمهای صفحه نسبت داده و یا آنها را آپدیت میکند. وقتی یک view باز استفاده میشود، دادههای قبلی بازنویسی میشوند.
Data source: هرچیزی که دوست داشته باشید- از یک آرایه ساده گرفته تا لیستهای بسیار پیچیده از دادهها. Adapter شما با آن تعامل میکند.
LayoutManager: مسئول قرار دادن تمامی آیتمها بر روی صفحه و اطمینان از اینکه به اندازه کافی فضا به هرکدام از آیتم ها تخصیص داده شده است میباشد.
مزایای RecyclerView:
- تنها آیتمهای قابل نمایش در صفحه، و چند آیتم یدکی دیگر bind میشوند، این یعنی علاوه بر اینکه همواره کارایی برنامه حفظ میشود، همواره تعدادی از آیتم ها برای نمایش آماده اند
- آیتم هایی که قبلا اسکرول شده و از صفحه خارج شده اند، ذخیره میشوند تا به محض نیاز، دوباره نمایش داده شوند. از طرف دیگر اگر همینطور به اسکرول در یک جهت ادامه دهید، هولدر هایی که خیلی عقب هستند، دوباره برای نمایش آیتم های جدید مورد استفاده قرار میگیرند، بدون اینکه حافظهی اضافی اشغال شود.
- وقتی که آیتمها تغییر کنند، میتوان با اطلاع رسانی به adapter و فراخوانی تابع notifyItemChanged باعث شد تا کدهای داخلی آداپتور تنها آیتمهای تحت تأثیر را آپدیت کند.
علاوه بر این شما میتوانید به شکل غیر ضمنی هم نماها را با کمک LayoutInflater، inflate کنید. برای اینکار باید:
1- یک نمونه از LayoutInflater بسازید.
2- فایل xmlی که میخواهید آن را inflate کنید مشخص کنید.
3- از view برگشت داده شده برای نمایش استفاده کنید.
اضافه کردن کتابخانه مربوط به پروژه
برای دسترسی و استفاده از RecyclerView، باید به شکل زیر V7 Support Libraries را به پروژه خود اضافه کنید:
1- فایل build.gradle را از بخش ماژولapp باز کنید
2- کتابخانه support را به بخش dependencies در این فایل اضافه کنید.
dependencies { implementation 'com.android.support:recyclerview-v7:28.0.0' }
اضافه کردن RecyclerView به layout
حالا میتوانید به فایل layout خود، RecyclerView را اضافه کنید. برای مثال، layout زیر از RecyclerView به عنوان تنها نمای مورد استفاده در کل layout استفاده کرده است.
<?xml version="1.0" encoding="utf-8"?> <!-- A RecyclerView with some commonly used attributes --> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent"/>
وقتی که RecyclerView را به layout خود اضافه کردید، یک واسط به آن ایجاد کنید، یک layout manager را به آن نسبت دهید و یک adapter برای داده ها به آن نسبت دهید تا نمایش داده شوند:
public class MyActivity extends Activity { private RecyclerView recyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager layoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_activity); recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView recyclerView.setHasFixedSize(true); // use a linear layout manager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); // specify an adapter (see also next example) mAdapter = new MyAdapter(myDataset); recyclerView.setAdapter(mAdapter); } // ... }
افزودن یک آداپتور به شکل لیست
برای نمایش تمامی دادههای خود به شکل لیست، باید از RecyclerView.Adapter ارث بری کنید. این شیء برای آیتمها نمایش (view) تولید میکند، و وقتی برخی از آیتمهای اولیه در محدودهی دید نباشند، محتویات آنها را با دادههای جدید عوض میکند.
کدی که در ادامه میآید، یک پیادهسازی ساده از نمایش آرایهای متشکل از string که با TextView نمایش داده میشوند است:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { private String[] mDataset; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder public static class MyViewHolder extends RecyclerView.ViewHolder { // each data item is just a string in this case public TextView textView; public MyViewHolder(TextView v) { super(v); textView = v; } } // Provide a suitable constructor (depends on the kind of dataset) public MyAdapter(String[] myDataset) { mDataset = myDataset; } // Create new views (invoked by the layout manager) @Override public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // create a new view TextView v = (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.my_text_view, parent, false); ... MyViewHolder vh = new MyViewHolder(v); return vh; } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(MyViewHolder holder, int position) { // - get element from your dataset at this position // - replace the contents of the view with that element holder.textView.setText(mDataset[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return mDataset.length; } }
layout manager، تابع onCreateViewHolder() در آداپتور را فراخوانی میکند. این متد باید یک RecyclerView.ViewHolder ساخته و نمایی را که برای نمایش محتویاتش مورد استفاده قرار میگیرد را تنظیم کند.
نوع ViewHolder باید با نوعی که در امضای کلاس Adapter تنظیم شده است، یکسان باشد. عموما، تنظیم view با inflate کردن یک فایل layout انجام میگیرد. به این دلیل که view holder هنوز به هیچ دیتای مشخصی نسبت داده نشده است، این تابع درواقع محتوای نما را تنظیم نمیکند.
سپس، layout manager، شیء view holder را به دیتای خودش متصل میکند. این کار را با فراخوانی onBindViewHolder() در adapter و ارسال مکان (position) شیء view holder در RecyclerView انجام میدهد.
تابع onBindViewHolder() نیاز دارد تا دادهی مناسب را پیدا کند و از آن برای تنظیم کردن layout مربوط به view holder استفاده کند. برای مثال، اگر RecyclerView لیستی از نامها نمایش میدهد، این تابع ممکن است نام مناسب را در لیست پیدا کند و ویجت TextView را در view holder مقداردهی کند.
اگر لیست نیاز به آپدیت داشت، با فراخوانی یکی از توابع اطلاع رسانی (notification) بر روی شیء RecyclerView.Adapter؛ مثل notifyItemChanged() ، شیء layout manager هرکدام از نماهای تحت تأثیر را آپدیت میکند.
منابع:
Kotlin & RecyclerView for High Performance Lists in Android