RecyclerView.Adapter<RecyclerAdapter.ViewHolder> confusion - java

I have been learning how to use RecyclerView in android studio. I came across a class extending "RecyclerView.Adapter < RecyclerAdapter.ViewHolder >". What is RecyclerAdapter.ViewHolder and why is it inside the brackets?

View holder objects:
They are instances of a class you define by
extending RecyclerView.ViewHolder. Each view holder is in charge of
displaying a single item with a view. For example, if your list shows
music collection, each view holder might represent a single album.
Adapters:
The view holder objects are managed by an adapter, which you create by
extending RecyclerView.Adapter.
When you extend the RecyclerView.Adapter, you have to specify what kind of view holder you want the adapter use. You do this inside < >. Read up on Generics to better understand this syntax.
https://developer.android.com/guide/topics/ui/layout/recyclerview

android uses the single view multiple times if list goes byond the screen .
viewHolder is the reference to that view .
when you scroll the list the system will use the previously ganerated views [referenced by the viewHolder with different values init].
watch this

Related

How to create a ListView with data in a List<objet> - Android Studio

I've started to learn mobile app development with Java and Kotlin (using Android Studio) and I'm stuck with something:
Ihave a kotlin class in a file, this is the code:
data class Clients (
val Id: Long,
val name: String,
val phoneNumber: List<String>,
val avatar: Uri?
);
and I have this code in the MainActivity(Java):
List<Clients> infos = InfosKt.retrieveAll(getApplicationContext());
My ListView code in my MainActivity:
ListView list_clients;
list_clients = findViewById(R.id.list_allclients);
I just want to know, How Can I put the data from List in a ListView ? The idea is that users see the Name and Phone numbers of all Clients.
Is there a way to convert the List in an Array ?
You need to put the actual items in the list - you do with with an Adapter, where you actually create a View and put the data in it.
There's an example on the Android developer site (not in Kotlin for some reason but you'll get the idea):
private class MyAdapter extends BaseAdapter {
// override other abstract methods here
#Override
public View getView(int position, View convertView, ViewGroup container) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
}
((TextView) convertView.findViewById(android.R.id.text1))
.setText(getItem(position));
return convertView;
}
}
What's basically happening is whenever the ListView needs to create an entry, it calls getView in the adapter. That inflates a list item layout, which you need to create - TextViews for your name and phone number, an ImageView for your avatar, that kind of thing.
Then you just find those views and fill them with your data - getItem is passing in a position value for the item's position in the list, so you use that to grab the right data object out of your array, and then you can set up your views to display it.
So you write that class, then call setAdapter(MyAdapter()) and the ListView will use it.
Someone recommended RecyclerViews instead, they are more efficient and the way you're supposed to do things, but they're also way more complicated. So I think this is the best way to learn the basic idea of making a layout, inflating it and filling it with data. Once you understand that, all the RecyclerView boilerplate will be a little easier to handle!

How Android Custom Adapter works?

I'am trying to use a custom listView in my application and i have some questions about its working principles.When i implemented a custom adapter,how its methods(especially the getView method)work without calling them from any other class ?
When you set the adapter to a view (e.g. ListView or GridView), that view at some point wants to have some items to show. So it calls getView in the adapter:
getView(int position, View convertView, ViewGroup parent).
The position is the position of the item in the list/grid/etc. The convertView is a recycled view that can be already inflated by a previous getView() call, or null when it's not inflated yet (see this answer about convertView and view recycling.
The parent is used to inflated the view, so the correct layout parameters can be computed in relation to the parent view.
Note that inflation is slow. That is why the convertView mechanism exists, to recycle views so the number of inflations is minimized. Next to that, finding views (findViewById()) is also relatively slow. To improve on that, check out the ViewHolder pattern, which keeps references to views in memory so they don't have to be searched for each time.
I think this link can help you. getview is a callback function which will be called automatically when you will display your listview on Activity. When you display your listview then you overrides getview and inflates your row from XML or dynamically creates your row. That row you return as a view which displays in your listview.
How does the getView() method work when creating your own custom adapter?
For each row getview will be called once. You create your layouts and return them as view. Those respective views displays in your lisview rows.
You are calling the custom adapter class from you activity class.Your customised adapter class extends a BaseAdapter which is an abstract class.The methods of an abstract will be used by the extended class(the methods like getView(), getItemId(), getItem(), and getCount()).These methods should not need a seperate call from your Class since you are calling the customised adapter classs .

List Adapter and getView function explanation

I'm thoroughly confused about the life cycle of list view. More specifically, what does the list adapter do exactly? Does it just provide data to the given view? And when/where does the getView() function gets called? And what purpose does this getView() function provide? From just looking at the code, it looks like getView() is "assigning" data to the view to be displayed. I'd like to be able to use list views without having to memorize, do this and then this in order for it to work. I'd much rather understand it so I can use it properly. Someone please help me understand all of this.
Also, if someone can explain to me.. what's the difference between BaseAdapter and ArrayAdapter? and any other kind of adapters that comes with Android.
What I have understood is your adapter constructor instantiated by activity and then on activity launch the getView() method is called. the {#param position, view, viewGroup}
position: it refers to the position of the view as given by adapter. Please Note it is different from the position in {OnItemClick(AdapterView adapter, View v, int position,long id)} here position is the list item position. The {position} in {getView()} changes after particular object in the list are displayed again for eg. when you scroll.
view: the view here is the view you want to be presented through getView(). It can be a particular XML layout for each row. So this states clearly that getView is called to plot every row. this view needs to be valid one or another layout (LinearLayout by default) will be selected to maintain uniqueness.
viewgroup: as you might know and as name says will be the container of your #param:view
any other point is appreciated.
getView() fills in the data into the item's view with the given index. The view which is given as a parameter may be a pre-inflated view. If it is not, you have to infalte it yourself.
An ArrayAdapter simply calls setText on the given view with the result of toString() of the object with the respective index from the array. If you override it, you can do more complex stuff, like assigning a picture or filling in more TextViews.
I recommend the following tutorial: http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
Hi list adaper provides view for listview.
when user scrolls listview at that time getview is called.
getview is used to populate your view with data hence the name adapter.
The Adapter does all the "rember to do this" for you. If you change a list view's backing data structure through the adapter's methods (e.g. "add()") it will fire all the datachanged and update events you'll need for the list view to show the new state of the data.

Android Binding strategy, should the adapter do the work, or the view?

I'm not sure if this is just something that is up to developer opinion but I am creating an android app and have a Listview that displays a custom view. My layout basically consists of a View (as an xml resource file and a class that derives from the view that is the root), a Domain Model object (has the data to be bound to the view) and an adapter which derives from BaseAdapter that binds the data from the Domain Model to the View in the getViewMethod as follows:
Model: SampleItem
Custom View: SampleView
Adapter: (code below)
public View getView(int position, View convertView, ViewGroup parent) {
SampleView sampleView;
SampleItem item = (SampleItem)getItem(position);
if(convertView == null) {
sampleView = new SampleView(_context);
}
else {
sampleView = (SampleView)convertView;
}
sampleView.setTitle(item.getTitle());
sampleView.setContentText(item.getContent());
sampleView.setItemRowNumer(item.getRowNumber());
... //etc
return sampleView;
}
This is how I've always seen it done, but I wonder is this the right way to do it.
My thought, coming from a different approach to data binding, is that the actual view class doesn't have a concept of what it's model is, and diverting the control to how data is bound to it to an adapter class that may not exist if moved elsewhere.
I was thinking that the custom view class has a reference to the object that is bound to it and in it's constructor it populates the view based on the data. So the adapter is essentially a shell class that only does this:
public View getView(int position, View convertView, ViewGroup parent) {
SampleView sampleView;
SampleItem item = (SampleItem)getItem(position);
if(convertView == null) {
sampleView = new SampleView(_context, item);
}
else {
sampleView = (SampleView)convertView;
}
return sampleView;
}
And the actual constructor for the view would know its model and populate itself as opposed to the Adapter doing work that seems outside of it's responsibility.
The adapter should do it. Two reasons.
1) CursorAdapter#bindView: it's defined in the framework. It's idiomatic and it will be what other android programmers would expect to see while reading your code. IMHO keeping things idiomatic improves code maintenance and legibility.
2) The way AdapterView classes work in android is that they reuse the Views returned from the adapter. This is so that a lot of new objects aren't created during scroll/flick/etc. animations and UI events. In order for that to work the AdapterView passes that View back to the adapter and expects that view to be reused. IMHO the intention and expectation is for the Adapter to handle updating and rebinding that View. If you attempt your method and keep the binding in the Views constructor then the only time data binding would happen would be in the constructor. You would then need to move that binding into a separate function possibly cluttering the class interface and with inheritance getting into other problems.
For me, I prefer that a View only care about how to display something. That's all the responsibilities I really want it to worry about. I think that's enough since some views can become quite complex. I like to leave it to other classes to worry about telling the View what it should be displaying and where that data should be coming from. Sometimes this means very simple bindings, i.e., calling toString() multiple times in a row. However, it decouples the data that is being displayed from the underling data which allows for one to change with the possibility of reusing the other.

How can I update one view at a time in an ArrayAdapter?

I want to be able to access my ArrayAdapter's view:
public View getView(int position, View convertView, ViewGroup parent)
I'm not sure how I can access this:
View myView = myArrayAdapter.getView(myPosition, myView, ?);
I am not sure how I can get a ViewGroup parent?
Well as far as I understand you don't suppose to Adapter in general serves as a source to instance of AdapterView so getView contract is follows :
in params : inPosition,convertView,viewParent
result : View witch will be shown at position inPosition , you can use convertView to bind data to if it's not null, returned view will be attached to viewParent.
So if you want to acquire view that will be shown by adapter view at specific position, why don't just call
AdapterView<?> adapterView = getAdapterView();
View myView = adapterView.getChildAt(position);
If you want to change way of showing view at specific position you should use
Adapter myAdapter = getAdapter();
//change data inside adapter
myAdapter.notifyDataSetChanged();
Update:
Try adding a field to the data in the data set that holds the background resource/color to be used when returning the view, and in the getView do
holder.background = dataSet.get(position).getBackground()
If you don't know what I'm talking about with this holder thing, check How to load the Listview "smoothly" in android
Old:
I'd say the ListView containing the adapter is the parent ViewGroup.
Anyway, why don't you use the ListView containing the ArrayAdapter? The ListView is the container of the Views, rather than the adapter, that only holds the data collection and creates and returns Views on demand when the ListView asks for them (f.e, when scrolling). Even if you were able to fetch a view for the position X, I'd say that won't work, as the convertView you pass as a parameter is not the one the ListView is holding and showing.
Take into account that in a ListView there are at most 7-8 Views inflated at any given moment (I don't know the exact number), and what the ListView does is fill them in by calling the adapter's getview.
This said, to update a single row (a single view) you'll need to update the adapter's data collection. Then, speculating, try to get that View from the ListView and invalidate it, but I doubt this'll work.
I think these concepts are right, if they are wrong I'd be grateful if anyone corrects me.
Why do you want to update only one view at a time?

Categories