Can someone tell me what the convertView parameter is used for in the getView() method of the Adapter class?
Here is a sample code take from here:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
Order o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("Name: "+o.getOrderName()); }
if(bt != null){
bt.setText("Status: "+ o.getOrderStatus());
}
}
return v;
}
What should we pass via convertView?
What I've found, take from here:
Get a View that displays the data at the specified position in the
data set. You can either create a View manually or inflate it from an
XML layout file. When the View is inflated, the parent View (GridView,
ListView...) will apply default layout parameters unless you use
inflate(int, android.view.ViewGroup, boolean) to specify a root view
and to prevent attachment to the root.
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.
parent -- The parent that this view will eventually be attached to Returns
returns -- A View corresponding to the data at the specified position.
You shouldn't be calling that method by yourself.
Android's ListView uses an Adapter to fill itself with Views. When the ListView is shown, it starts calling getView() to populate itself. When the user scrolls a new view should be created, so for performance the ListView sends the Adapter an old view that it's not used any more in the convertView param.
Related
The get view method from the script below crashes everytime I ran the app (the error points to that method ) this is the error :
07-11 17:25:01.147 8512-8512/com.example.android.quakereport E/AndroidRuntime:
FATAL EXCEPTION: main
Process: com.example.android.quakereport, PID: 8512
android.content.res.Resources$NotFoundException: Resource ID #0x0
and this is the ArrayAdapter from the getview method code :
public class EarthQuakeAdapter extends ArrayAdapter<Earthquake> {
public EarthQuakeAdapter(Activity context, ArrayList<Earthquake> Earthquakes) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, 0, Earthquakes);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false);
return super.getView(position, convertView, parent);
}
Earthquake currentEarthquake = getItem(position);
TextView magnitude = (TextView) listItemView.findViewById(R.id.magnitude);
// Get the version name from the current AndroidFlavor object and
// set this text on the name TextView
magnitude.setText(Earthquake.getmMagnitude());
// Find the TextView in the list_item.xml layout with the ID version_number
TextView place = (TextView) listItemView.findViewById(R.id.Place); // Get the version number from the current AndroidFlavor object and
// set this text on the number TextView
place.setText(Earthquake.getMplace());
// Find the ImageView in the list_item.xml layout with the ID list_item_icon
TextView date = (TextView) listItemView.findViewById(R.id.Date);
date.setText(Earthquake.getmDate());
// Get the image resource ID from the current AndroidFlavor object and
// set the image to iconView
// Return the whole list item layout (containing 2 TextViews and an ImageView)
// so that it can be shown in the ListView
return listItemView;
}
I can add any code or ressource if needed just tell me on the comments.
You're never really returning the ViewHolder you inflated.
You shouldn't call super when the view is null. You should inflate it, get the child views, populate them and finally return the inflated root view.
Take a look at the docs to learn more about this process.
Try to write the adapter like this:
public class EarthQuakeAdapter extends ArrayAdapter<Earthquake> {
// ...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
Earthquake currentEarthquake = getItem(position);
TextView magnitude = (TextView) listItemView.findViewById(R.id.magnitude);
// Get the version name from the current AndroidFlavor object and
// set this text on the name TextView
magnitude.setText(Earthquake.getmMagnitude());
// Find the TextView in the list_item.xml layout with the ID version_number
TextView place = (TextView) listItemView.findViewById(R.id.Place); // Get the version number from the current AndroidFlavor object and
// set this text on the number TextView
place.setText(Earthquake.getMplace());
// Find the ImageView in the list_item.xml layout with the ID list_item_icon
TextView date = (TextView) listItemView.findViewById(R.id.Date);
date.setText(Earthquake.getmDate());
// Get the image resource ID from the current AndroidFlavor object and
// set the image to iconView
// Return the whole list item layout (containing 2 TextViews and an ImageView)
// so that it can be shown in the ListView
return listItemView;
}
}
You can read more about smooth scrolling here on android's training page.
And as an option, you could switch to RecyclerView, you can read more about it here.
You shouldn't need to call super.getView(...) in the overridden getView function, and you're passing in an invalid resource ID. Simply remove that line, since you're not using its return value anyway:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false);
}
...
}
I know that there are similar questions, but i couldn't really understand, so i decided to ask again.
I am trying to do something similar to a chat, so in the list view there would be 2 types of rows, the ones of the received items and the ones of the sent items. The ones that were received will inflate the recvRow.xml layout, and the ones that were sent will inflate the sentRow.xml layout.
I have a list of items that are suposed to be shown ( name, img, etc) and i have a boolean that represents if the object was sent or received.
The problem is that those layouts have different buttons and if for example i receive something first, it will obviously load the recvRow.xml , but then if I try to send something, it will throw a nullpointerexception because on one of the buttons that only exists in the sentRow.xml layout (and doesn't exist in the recvRow.xml).
Since i am checking that boolean that i told you guys before, i don't see the need to use the getItemViewType method.
Here is my code for the getView method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
viewHolder = null;
if (convertView == null) {
viewHolder=new ViewHolder();
LayoutInflater layoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
System.out.println("Transf Rec Adapter : Going to draw AN ITEM : "+ listOfItems.get(position).getAppName());
System.out.println("Transf Rec Adapter : The received bool is : "+ listOfItems.get(position).isReceived());
if(listOfItems.get(position).isReceived()){
view=layoutInflater.inflate(R.layout.highway_transf_record_recv_row,parent,false);
viewHolder.deleteFile=(ImageView) view.findViewById(R.id.transfRecRowDelete);
viewHolder.installButton = (ImageView) view.findViewById(R.id.transfRecRowInstall);
}else{//se enviado
view=layoutInflater.inflate(R.layout.highway_transf_record_sent_row,parent,false);
viewHolder.reSendButton=(ImageView) view.findViewById(R.id.transfRecReSendButton);
}
viewHolder.appImageIcon=(ImageView) view.findViewById(R.id.transfRecRowImage);
viewHolder.appNameLabel=(TextView) view.findViewById(R.id.transfRecRowText);
viewHolder.appVersionLabel = (TextView) view.findViewById(R.id.transfRecRowAppVersion);
viewHolder.senderInfo = (TextView) view.findViewById(R.id.apkOrigin);
viewHolder.rowImageLayout = (RelativeLayout) view.findViewById(R.id.transfRecRowImageLayout);
viewHolder.appInfoLayout = (RelativeLayout) view.findViewById(R.id.appInfoLayout);
}else{
view= convertView;
viewHolder = (ViewHolder) convertView.getTag();
}
if(listOfItems.get(position).isReceived()){
System.out.println("INSIDE THE GET VIEW TRANSF REC ADAPTER : RECEIVED SOMETHING");
viewHolder.senderInfo.setText("You received this app :");
myOnClickListenerToInstall = new MyOnClickListenerToInstall(position);
viewHolder.installButton.setOnClickListener(myOnClickListenerToInstall);
myOnClickListenerToDelete= new MyOnClickListenerToDelete(position);
viewHolder.deleteFile.setOnClickListener(myOnClickListenerToDelete);
}else{
System.out.println("INSIDE THE GET VIEW TRANSF REC ADAPTER : SENT SOMETHING");
viewHolder.senderInfo.setText("You sent this app :");
ReSendListener reSendListener=new ReSendListener(position);
viewHolder.reSendButton.setOnClickListener(reSendListener);//null pointer exception here
}
viewHolder.appNameLabel.setText(listOfItems.get(position).getAppName());
viewHolder.appImageIcon.setImageDrawable(listOfItems.get(position).getIcon());
viewHolder.appVersionLabel.setText(listOfItems.get(position).getVersionName());
view.setTag(viewHolder);
return view;
}
The id's are right and everything exists on the viewHolder.
You need to use getItemViewType because of recycling. Otherwise you can try to recycle a received item into a non-received view, which will screw things up royally. However it is ok for getItemViewType to just return 0 or 1 based on that boolean. It doesn't need to be very complicated for 2 view types.
You should override getItemViewType() in your adapter. This method will indicate the type of view which should be inflated for each row. You also need to override getViewTypeCount().
I have a listview that contains items that have listviews. I am trying to populate item's listviews from inside the getView of the custom adapter that populates the "parent" listview:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
System.out.println("session adapter: here1");
if (v == null) {
LayoutInflater inflater = (LayoutInflater) act.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.single_session, null);
}
SessionObject i = sessions.get(position);
if (i != null) {
tvTrackName = (TextView) v.findViewById(R.id.textViewTrackName);
tvTrackName.setText(i.trackName);
tvSessionName = (TextView) v.findViewById(R.id.textViewSessionName);
tvSessionName.setText(i.sessionName);
tvSessionModerator = (TextView) v.findViewById(R.id.textViewModeratorName);
tvSessionModerator.setText("Moderator: "+i.sessionModerator);
listAbstracts = i.abstractList;
lvAbstracts = (ListView) v.findViewById(R.id.listViewAbstracts);
AbstractObjectAdapter adapter = new AbstractObjectAdapter(act, R.id.listViewAbstracts, listAbstracts);
lvAbstracts.setAdapter(adapter);
}
return v;
}
The "interior" adapter seems to only be calling its getView function once, regardless of the number of items in its list. If there are 2 items, only the first gets put into the listview. Is this the wrong way to do this? Am I missing something?
Any help is appreciated. Thanks.
Just create your item view dynamically, adding textviews to a linearlayout. You'll just have to be careful about handling the convertView, initially it will be easiest to always ingore it but you'll take a bit of a performance hit.
Optimise later.
I have to inflate the group of items in a listview and i need to find inflated view anywhere in the program .
May I know how to find the view.
How to set id and get id of inflated listview.
Thanks in Advance
In the Adapter of your list view
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.newlistrow, null);
//Access your inflated layout using vi
TextView sometextview= (TextView) vi.findViewById(R.id.textview); // sometextview
Typically you don't find views in a list view. The adapter behind the list view will pass you the view plus the underlying position of your data that you need to render via the getView method.
To answer your question of how to get or set id of inflated view you should call getId or setId on the inflated view.
http://developer.android.com/reference/android/view/View.html#setId(int)
http://developer.android.com/reference/android/view/View.html#getId()
View myView = LayoutInflater.from(activity).inflate(R.layout.list_item_punch_log, null);
myView.setId(android.R.id.button1);
int id = myView.getId();
However doing this and finding views in a list view is a very dangerous act as it will cause some really funny behaviors on the listview. Maybe you can tell us what you are trying to do and we can guide you from there.
I currently have a List View backed by a Simple Adapter. I am able to update the Simple Adapter values fine, however, they do not update on the list view unless the view goes off screen.. then when it returns to the screen it is updated. Ive tried everything like listview.refreshDrawableState and listview.invalidate to simpleadapter.notifyDataSetChanged and nothing makes it update on the screen, the views have to be scrolled off screen then back on to get updated.
Thank you to whoever responds =)
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.machine_list, null);
}
HashMap<String, String> map = machineListView.get(position);
if (map != null)
{
TextView status = (TextView)findViewById(R.id.statusText);
TextView numAlarms = (TextView)findViewById(R.id.alarmText);
if (status != null)
status.setText(map.get(status));
if (numAlarms != null)
status.setText(map.get(numAlarms) + " Alarms");
}
return v;
}
this may not be the best way but I simply reset the listView adapter whenever I want to refresh the whole view.