As per my understanding, the following things happen on a broad level when data is to be shown using the RecyclerView.
1) Recycler view calls the onCreateViewHolder() method which returns a ViewHolder object and then calls onBindViewHolder() which binds the data with individual views contained in the ViewHolder.
Doubt:
As RecyclerView object never gets the total inflated View of the XML file, It only gets the views wrapped inside the ViewHolder object. How is RecyclerView able to draw the ViewHolder views correctly? Do the individual Views present in the ViewHolder have sufficient information about their parent layout, padding, margin, where they should be placed in their parent layout?
RecyclerView contains some components.
Adapter (Provide data)
View Holder (Provide view for binding data)
LayoutManager (Locate position of each item)
and others.
You could read this article to deep inside RecyclerView. (Link)
The main point which I missed here is that the custom ViewHolder class which we define is an extended version of base class RecyclerView.ViewHolder class which holds the actual reference to the inflated View. The constructor of this class receives the View object reference which we created by inflating the XML file of the row to be displayed. Hence this View object which represents the entire hierarchy of the row file layout is saved as an instance member which is named as itemView in the android defined base class (RecylclerViewer.ViewHolder).
class MyViewHolder extends RecyclerView.ViewHolder
{
MyViewHolder(View itemView)
{
/* We are calling the base class constructor passing the Entire View hirerachy */
super(itemView)
}
}
When we extend the ViewHolder class, we add additional View members in this class (like TextView, Buttons etc.) which is an optimisation so that while binding the data in onBindViewHolder(), we can avoid calls to findViewById on the parent View object.
Thus our custom ViewHolder object not only wraps the sub view objects but also holds / wraps the reference to the entire inflated View. Because of this, RecyclerView is able to draw the row completely.
Related
I have a use case...
I want to get layoutInflator to bind different Views for nested recyclerView. Is there any best way to get layoutInflator?
I was trying to get it from onBindViewHolder
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder. //something?
}
You shouldn't be inflating anything in onBindViewHolder - onCreateViewHolder is where you set up a ViewHolder object that displays a list item, including inflating its layout views. onBindViewHolder is where you interact with those views, to display the appropriate data for the current item.
Those created ViewHolders get reused, so instead of inflating views for every item, you just create a handful of ViewHolders that get swapped around as you scroll the list. That recycling of a pool of VHs is why it's called a RecyclerView.
Generally, you'd store references to the inflated views inside each ViewHolder, like in this example:
/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder)
*/
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView
init {
// Define click listener for the ViewHolder's View
textView = view.findViewById(R.id.textView)
}
}
That way, the ViewHolder that gets passed into onBindViewHolder has a textView field you can access, e.g. to set its text contents to display data for the current item. (If you're using View Binding, you could store a reference to the binding object instead, and access the views through holder.binding.textView etc)
I don't know what you're doing with nested RecyclerViews, but the principle is the same - each ViewHolder in the main RV will contain another RV, with its own adapter and data set, created and initialised in onCreateViewHolder. If you want to change its contents (because you're displaying a particular item in the main RV list) you'd probably want to add a setData function on the nested RV's adapter that changes its data set and refreshes the display. Let the adapter handle inflating things when it needs to, inside onCreateViewHolder
I use a RecyclerView to display a list of items. The RecyclerView shows a single item at the time. By clicking a button I would like to change ViewHolders for all the items, including the one displayed. The data stays the same, only the list item layout changes.
I supposed I need to clear the cache pool, but it did not help. There are still views in the recycler pool.
recyclerView.recycledViewPool.clear()
RecyclerView keeps using the cached views.
Moreover, how to re-create the view with a new ViewHolder of the item displayed?
add type in your model class
var viewType : ViewType
make an enum of viewType
ViewType { VIEW_ONE, VIEW_TWO }
override ItemViewType function in your RecyclerViewAdapter. Make separate Layout files for each view type and create/inflate in onCreateViewHolder of RecyclerViewAdapter.
When button is being pressed. Change the ViewType in your model class and call notifyDatasetChanged()
I have a requirement as shown in this image.
I have 2 show 2 object data on single row. Normally we show these information as one object in one row. How could we achieve it.
You can use,
GridView
RecyclerView with GridLayoutManager
You can achieve it customizing getView() method in listview adapter.
what getView() method do?
getView() normally generates view for each row in a general sense.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//inside this we populate data using position value
}
Here you need to show two object (sequence or random) data in a single row. You need to use another int variable to keep track about object size.
initialize it on top, int i = 0;
inside getView() you need to do something extra because you need to populate 2 object data on a single getView() method call.
Create 2 object and populate data using i.
increment i value after every object creation.
Put an if condition do check i value is less than your array size. Its because getView() method will call based on your array size and you need to populate data half / less of that.
****Populate data inside above if condition.
*Better you try Gridview for this type of needs.
*Custom layout GridView example
You need ListView xml, ListItem xml, ListItem class (object), ArrayAdaper class
Set a row view and items in that view in ListItem xml.
Create ListItem class (object) with variables (Such as String, int) you needed.
Bind the view and item in ArrayAdapter class.
I have a listview with two columns where the user can compare the productName and proudctQty against the stock. There are loads of products in that list and the user may get confuse checking all of them. So, the idea is to highlight the products and their price by using focus.
Does anyone know if would be possible to implement it in listview like on the virtual keyboard (it isnot onLongTouch or click)?
Could anyone give a hint about how to do it?
Many thanks
ok like in case of wheelpicker iPhone we can highlight the product just follow these steps
implement the list's onscrollchangedlistener .
put the list in a relative layout with another view at the centerinparent and fillparent
on this view you will display the highlighted item.
as the list is scrolled update the content over that view inside the overrided onscroll method.
You need to use a View Holder Pattern. You can find more information on Google.
Simply create a class called AdapterViewHolder, declare properties, the Views on each row.
For example:
public class AdapterViewHolder
{
ImageView myImageView;
TextView myTextView;
...
}
In constructor pass your values to set to the views, initialize your views and set your values like:
public AdapterViewHolder(String param, Drawable imageDrawable){
// set values to views
}
In the adapter in getView method:
if convertView == null
//then create your layout and holder class, set your holder to your layout by view.setTag method, prepare your view and return it
else
//get your layout tag by view.getTag(), cast it to AdapterViewHolder and update your views and values of them as you like and then return updated view.
For more info search for ViewHolder Pattern in android listviews.
public class CustomAdapter extends BaseAdapter
I found a code that extends BaseAdapter
public View getView(int index, View view, final ViewGroup parent) {
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(R.layout.single_list_item, parent, false);
}
}
TextView textView = (TextView) view.findViewById(R.id.tv_string_data);
textView.setText(dataModel.getName());
my question is when view == null ?
why we need the code if (view == null) {}
thanks
A ListView typically contain more data then the number of displayed rows. If the user scrolls the list then rows and their associated Views will be scrolled out of the visible area. The Java objects which represents the rows can be reused for newly visible rows.
If Android determines that a View which represents a row is not visible anymore it allows the getView() method to reuse it via the convertView parameter.
A performance optimized adapter assigns the new data to the convertView. This avoids inflating an XML file and creating new Java objects.
In case no View is available for reuse, Android will pass null to the convertView parameter. Therefore the adapter implementation need to check for this.
For the first item in the listView the View will be null. It needs to be inflated for the first item.
Please be free to ask any further doubts.
Android re-cycles View objects to minimize object creation and memory usage. The View that is passed to you will either be null, in which case you are expected to create it, or the view will be non-null which means it has been re-cycled. Re-cycled views are ones that you may have created earlier, but can now be used for a different purpose.
A good example of this is a listview. A list may have many elements, say 100. The screen however may only display 10 items of the list. Thus when you scroll the screen, views that were for items no longer on the screen may be passed to you for re-use. This is re-cycling.
For list view we have to provide view for each and every item, and also we have to fill contents also. In most cases the same view will be repeated in every item with different content. So at the first time in getView method we will check, if view is null then we should inflate a view and fill the contents and return. At second time the view will not be null. So you can reuse or provide different view.