How Android Custom Adapter works? - java

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 .

Related

Get UI Element ID In a Fragment From Custom adapter

I'm developing an android app and I have a fragment that contains TextView & ListView in it. The list view has custom list items that contains two buttons. I want to make 'onClickListener' for one of those two buttons in my custom adapter class to change the text of the TextView, but I can't access it by findViewById() every time I try I got null exception.
My guess is that you're trying to access the TextView from inside of the Adapter.
If so, then you won't be able to get the TextView and it's normal to get a nullpointer exception.
The findViewById inside your adapter only finds the views that you have inflated in the getView() method of your adapter.
What you can do here is probably use an interface that's implemented by your Fragment to pass the information from your adapter back to the fragment.
This answer might be a good starting point : How to create interface between Fragment and adapter?

RecyclerView.Adapter<RecyclerAdapter.ViewHolder> confusion

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

Explanation of the getView() method of an ArrayAdapter

Could you explain the getView() method of an ArrayAdapter.
I read the docs and it has three parameters:
position: The position of the item within the adapter's data set of
the item whose view we want.
convertView: The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view.
Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).
parent: The parent that this view will eventually be attached to
I understood the position parameter. Like they said, it's imply the position of the item, who view has been requested.
Where does convertView come from. I've seen many examples where they check if convertView is null. If is is null, they inflate a new instance of the row layout, populate it and return it. I guess I've gotten my head around that too but one thing still baffles me. What is the layout that is passed in through the convertView parameter. Is if the resource parameter that is passed in when initialising the ArrayAdapter? Is is a cached copy of the last layout returned by getView()?
And lastly. What does the parent parameter do. I haven't seen too many examples utilising this. Most of them simply reuse/inflate a row layout and return it.
(I'm asking because I have an on-click animation in my ListView. Specifically this one that aims to replicate Spotify's dropdown quick action menu. My animation has been a little sluggish. After diagnosing this issue for a while, I've realized that this has been due to the fact that my getView() method takes a bit of time to complete as I'm inflating a fresh row layout in every iteration. Someone suggested caching the row layout in a ViewHolder while other examples point to reusing the convertView parameter i.e. only inflating a row layout if convertView is null.)
Is is a cached copy of the last layout returned by getView()?
The convertView is the view of a row that left the screen(so it isn't the last view returned by the getView method). For example, the list is first shown, in this case convertView is null, no row view was previously built and left the screen. If you scroll down, row 0 will leave the screen(will not be visible anymore), when that happens the ListView may choose to keep that view in a cache to later use it(this makes sense, as the rows of a ListView generally have the same layout with only the data being different). The reason to keep some views in a cache and later use them is because the getView method could be called a lot of times(each time the user scrolls up/down and new rows appear on the screen). If each time the row view would need to be recreated this would have resulted in a lot of objects being created which is something to avoid. In your getView method you would check convertView to see if it is null. If it's null then you must build a new row view and populate it with data, if it isn't null, the ListView has offered you a previous view. Having this previous view means you don't need to build a new row layout, instead you must populate it with the correct data, as that cached view has the old data still attached to it(you would see a lot of questions on stackoverflow where users ask why the rows of their ListView are duplicating when they scroll down).
What does the parent parameter do. I haven't seen too many examples
utilising this. Most of them simply reuse/inflate a row layout and
return it.
It should be used to get the correct LayoutParams for the newly inflated/built row. For example, if you inflate a layout which has a RelativeLayout as the root and you don't use the parent to get the LayoutParams you could have some problems with the row layout. To take the parent in consideration you would use :
convertView = getLayoutInflater().inflate(R.layout.row_layout, parent, false);
My understanding of convertView is that it's essentially views that have been recycled because they're not being used at the moment - for example, you scroll down the list, the ones at the top aren't on the screen, so they get passed into this parameter for use when you need a new view (so you don't have to create a whole new one while having unused ones sitting around idle). iOS has a similar method called dequeueReusableCellWithIdentifier. If each row of your listview has the same structure, it's safe to cast this to the appropriate type and just update the information in it - text, images, etc. It will be a View that was previously returned by a getView() call for the same list.
My best guess (and it is admittedly a guess) with parent is that it's the view that this adapter's list is a child of. It gives you a route back to the rendering system if you need a context, access to the resource system, to pass information to or receive information from the list's parent view.

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.

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