GridView CustomGrid Adapter repeats items - android

Hey i'm using gridView to show my items. Everything is ok but after six items or scroll some items get repeated.
So i think i have something to do in case the convertItem is not null. But how i load next items
Some short code:
public CustomGridAdapter(Context context, ArrayList<Event> finalResult, double latitude, double longitude) {
this.posLatitude = latitude;
this.posLongitude = longitude;
this.context = context;
this.gridValues = finalResult;
this.app = new Application(context);
}
#Override
public int getCount() {
return gridValues.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// LayoutInflator to call external grid_item.xml file
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
gridView = inflater.inflate(R.layout.grid_item, null);
event = gridValues.get(position);
} else {
gridView = convertView;
}
return gridView;
}

ConvertView is by definition being reused. Make sure to change the values of the view item inflating or setting it.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// LayoutInflator to call external grid_item.xml file
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = inflater.inflate(R.layout.grid_item, null);
} else {
gridView = convertView;
}
event = gridValues.get(position);
// TODO: set view values based on this event
return gridView;
}

Related

ListView Custom Adapter repeat items

Whats wrong with this adapter, when i scroll down i see repeated rows at the bottom and then when scroll up again i see also repeated rows at the top that were not exist before, and the rest of Data items does not appear
the adapter:
public class ClassesListViewAdapter extends BaseAdapter {
private Context mContext;
ArrayList<String> Data = new ArrayList<>();
public ClassesListViewAdapter(Context context, ArrayList<String> data) {
Data = data;
mContext = context;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getCount() {
return Data.size();
}
private class ViewHolder{
TextView ClassDataTV;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.classes_list_view_item, parent, false);
holder = new ViewHolder();
holder.ClassDataTV = (TextView) convertView.findViewById(R.id.ClassDataTV);
holder.ClassDataTV.setText(Data.get(position));
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
return convertView;
}
}
and here how i use it:
ArrayList<String> v = new ArrayList<>();
v.add("AAAAAAA");
v.add("WWWWWwW");
v.add("VVVVVVV");
v.add("SSSSSSSSS");
v.add("QQQQQQQQQ");
v.add("YYYYYYYY");
v.add("TTTTTTT");
v.add("UUUUUUUUUU");
v.add("zzzzzzzzzzzz");
v.add("CCCCCCCCCC");
v.add("HHHHHHHHHHH");
v.add("IIIIIIIIII");
v.add("PPPPPPPPP");
mListView.setAdapter(new ClassesListViewAdapter(getActivity(), v));
Put following part of your code outside if-block and it will be fixed :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.classes_list_view_item, parent, false);
holder = new ViewHolder();
holder.ClassDataTV = (TextView) convertView.findViewById(R.id.ClassDataTV);
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
// initialize your view here
holder.ClassDataTV.setText(Data.get(position));
return convertView;
}
The logic behind ViewHolder pattern tells that you should do it in this way. when you scroll some of reference will not created again and else block called so this cause your list not updated as you expected.

ListView items repeat in BaseAdapter

I'm pulling data and loading it into a BaseAdapter for my List View. Currently, the items in the listview are the same as the last item added, so the list looks like this:
Item 3
Item 3
Item 3
Instead of:
Item 1
Item 2
Item 3
I've checked over the data sources, and the data that's loaded from the source is unique each time. I think there's somehting wrong with my BaseAdapter, but I'm not sure what it is. Here's my BaseAdapter:
BaseAdapter.java
ArrayList<ThreadListData> myList = new ArrayList<>();
LayoutInflater inflater;
Context context;
public ThreadBaseAdapter(Context context, ArrayList<ThreadListData> myList) {
this.context = context;
inflater = LayoutInflater.from(this.context);
this.myList = myList;
}
#Override
public int getCount() {
return myList.size();
}
#Override
public ThreadListData getItem(int position) {
return myList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(this.context);
convertView = inflater.inflate(R.layout.listitem_newthread, parent, false);
}
ThreadListData listData = getItem(position);
TextView name = (TextView)convertView.findViewById(R.id.name_newthread);
TextView username = (TextView)convertView.findViewById(R.id.username_newthread);
name.setText(listData.getName());
username.setText(listData.getName());
ParseImageView profile = (ParseImageView)convertView.findViewById(R.id.profilepicture);
BitmapTask task = new BitmapTask(listData.getImage());
task.execute(profile);
return convertView;
}
I'll start with my BaseAdapter, and can show more code if requested. All Help Is Appreciated!
You missed to return the position
Modifiy your getItemId as
#Override
public long getItemId(int position) {
return position;
}
There are 2 things you need to change:
1. You return wrong item position
#Override
public long getItemId(int position) {
return 0;
}
It should be
#Override
public long getItemId(int position) {
return position;
}
2. Your declared a LayoutInflater and create new instance in constructor. But in the getView(), you create another LayoutInflater. Look at updated code below
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
// LayoutInflater inflater = LayoutInflater.from(this.context);
inflater = LayoutInflater.from(this.context);
convertView = inflater.inflate(R.layout.listitem_newthread, parent, false);
}
ThreadListData listData = getItem(position);
TextView name = (TextView)convertView.findViewById(R.id.name_newthread);
TextView username = (TextView)convertView.findViewById(R.id.username_newthread);
name.setText(listData.getName());
username.setText(listData.getName());
ParseImageView profile = (ParseImageView)convertView.findViewById(R.id.profilepicture);
BitmapTask task = new BitmapTask(listData.getImage());
task.execute(profile);
return convertView;
}

Grid View - first item on first and last position

I have a fragment with gridview:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
context = container.getContext();
View window = inflater
.inflate(R.layout.shop_fragment, container, false);
gridView = (GridView) window.findViewById(R.id.shop_root_view);
gridView.setAdapter(new ShopAdapter(context, GRID_DATA));
gridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(
context,
((TextView) v.findViewById(R.id.grid_item_label))
.getText(), Toast.LENGTH_SHORT).show();
}
});
return window;
}
And adapter:
public class ShopAdapter extends BaseAdapter {
private Context context;
private final String[] gridValues;
// Constructor to initialize values
public ShopAdapter(Context context, String[] gridValues) {
this.context = context;
this.gridValues = gridValues;
}
#Override
public int getCount() {
return gridValues.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
// Number of times getView method call depends upon gridValues.length
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// LayoutInflator to call external grid_item.xml file
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
// get layout from grid_item.xml ( Defined Below )
gridView = inflater.inflate(R.layout.item_grid_shop, null);
// set value into textview
TextView textView = (TextView) gridView
.findViewById(R.id.grid_item_label);
Log.d("Shop", "pozycja: " + position);
textView.setText(gridValues[position]);
// set image based on selected text
ImageView imageView = (ImageView) gridView
.findViewById(R.id.grid_item_image);
imageView.setImageResource(R.drawable.ic_launcher);
} else {
gridView = (View) convertView;
}
return gridView;
}
}
Every time I open that fragment, item from GRID_DATA appears on first and last position. Last item from GRID_VIEW does not appear. How to solve this? This is just example code, which I found on internet.
The convertView usage is wrong here.
You should use it differently:
- If is null, inflate the view
- If not, do nothing (and will use it)
Then you close that bracket and set your data.
Try this:
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_grid_shop, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.grid_item_label);
Log.d("Shop", "pozycja: " + position);
textView.setText(gridValues[position]);
ImageView imageView = (ImageView) convertView.findViewById(R.id.grid_item_image);
imageView.setImageResource(R.drawable.ic_launcher);
return convertView;
}

Listview: Only one list item with multiple textviews

I need to show multiple text views in only one list item and the rest of the list view items will have just one textview.
How do I achieve this? Any samples or tutorials you can point me at?
Thank you.
Make your own adapter:
BaseAdapter already provieds methods for working with different View types (different layout for list item cells) and to effektivly recycle views:
getViewTypeCount(): The count of how many different Views (layouts) are present.
getItemViewType(): Returns a integer to identify the view type of the item in the cell. Note the internally BaseAdapter implementation uses an array. Therefore your values returned here must be from 0 to n. You are not allowed to skip indexes.
public class MyAdapter extends BaseAdapter {
private final int VIEW_TYPE_NORMAL = 0;
private final int VIEW_TYPE_4_TEXTS = 1;
/**
* The inflater for
*/
protected LayoutInflater inflater;
protected Context context;
public MyAdapter(Context context) {
this.context = context;
this.inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getViewTypeCount() {
// There are two view types
return 2;
}
#Override
public int getItemViewType(int position) {
if (position == 0)
return VIEW_TYPE_4_TEXTS;
else
return VIEW_TYPE_NORMAL;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
if (convertView == null) {
convertView = newView(type, parent);
}
bindView(position, type, convertView);
return convertView;
}
#Override
public long getItemId(int position) {
return 0; // replace it with your id, if you have stable ids in your
// adapter
}
/** Inflates the correct view accorind the view type **/
public View newView(int type, ViewGroup parent) {
if (VIEW_TYPE_4_TEXTS == type) {
View view = inflater.inflate(R.layout.your_layout_with_4_textviews,
parent, false);
view.setTag(new ViewHolder4TextViews(view)); // ViewHolder pattern
return view;
}
// Otherwise its a normal item with VIEW_TYPE_NORMAL
View view = inflater
.inflate(R.layout.your_normal_layout, parent, false);
view.setTag(new NormalViewHolder(view)); // ViewHolder pattern
return view;
}
/** Bind the data for the specified {#code position} to the {#code view}. */
public void bindView(int position, int type, View view) {
if (VIEW_TYPE_4_TEXTS == type) {
// set the 4 text view values
ViewHolder4TextViews holder = (ViewHolder4TextViews) view.getTag();
holder.textview1.setText("...");
holder.textview2.setText("...");
holder.textview3.setText("...");
holder.textview4.setText("...");
} else {
// VIEW_TYPE_NORMAL
NormalViewHolder holder = (NormalViewHolder) view.getTag();
holder.textview.setText("...");
}
}
}
Use a custom adapter for you list and edit the getView function:
public class MyListAdapter extends BaseAdapter {
[...]
#Override
public View getView(int position, View view, ViewGroup parentView) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(position < 1) {
/* Inflate a layout with 4 textview */
view = inflater.inflate(R.layout.your_4_textview_layout, parentView, false);
} else {
/* Inflate a layout with 1 textview */
view = inflater.inflate(R.layout.your_1_textview_layout, parentView, false);
}
return view;
}
[...]
}
Take care about pass Context context to MyListAdapter in constructor like this answer
You can make changes in your adapter...some thing like this.
#position 1: "blank" view will be diplayed
#rest positions: "triplistrow" will bw displayed
#Override
public View getView(final int position, View convertView, final ViewGroup parent)
{
View rowView = convertView;
if(position !=1)
{
if (rowView == null)
{
LayoutInflater inflater = context.getLayoutInflater();
rowView = inflater.inflate(R.layout.triplistrow, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.no = (TextView) rowView.findViewById(R.id.TVTripNo);
viewHolder.name = (TextView) rowView.findViewById(R.id.TVTripName);
viewHolder.date = (TextView) rowView.findViewById(R.id.TVTripDate);
rowView.setTag(viewHolder);
}
}
else
{
LayoutInflater inflater = context.getLayoutInflater();
rowView = inflater.inflate(R.layout.triplistrow, null);
ViewHolder viewHolder = new ViewHolder();
rowView.setTag(viewHolder);
}
if(position!=1)
{
final ViewHolder holder = (ViewHolder) rowView.getTag();
holder.no.setText(String.valueOf(position+1));
holder.name.setText(values.get(position).name);
holder.date.setText(values.get(position).fromdate + " to " + values.get(position).tilldate);
}else
{
}
return rowView;
}

ArrayAdapter goes beyond bounds

I have an ArrayAdapter with ArrayList filled. Each time I click on any of its item I re-fill the ArrayList and send notifyOnDataSetChange() to the adapter. But for unknown for me reason it goes out of ArrayList bounds in it's getView() method where it populates its items. I don't understand why this happens. Can you guys explain the theory of getView() invokation so I understand why this going on. Thanks in advance!
Here it is:
class MAdapter extends ArrayAdapter<String> {
public MAdapter(Context context, int textViewResourceId, List<String> objects) {
super(context, textViewResourceId, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.file_explorer_row, null);
} else {
}
String txt = itemsList.get(position); // Out of bounds happens here
if (!txt.equals("")) {
TextView tt = (TextView) v.findViewById(R.id.file_explorer_tv_filename);
tt.setText(txt);
}
return v;
}
itemsList is declared in Outer Class.
change like this
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null)
{
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.file_explorer_row, parent, false);
}
Though i am not getting a clear view of what you are asking..i am assuming that , you are refilling the entire ArrayAdapter again....
So try this.........
Use removeView() on ListView before setting the adapter to it...
Eg:
ListView.removeView();
ListView.setAdapter(yourAdapter);
String txt = itemsList.get(position);
itemsList.get(position) returns a Integer Value and that you are try to store in a String..this might be the reason.
Try this code:
class MAdapter extends BaseAdapter {
List<String> objects;
Context context;
public MAdapter(Context context,List<String> objects) {
super();
this.context=context;
this.objects=objects;
}
public int getCount() {
return objects.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
Holder holder;
LayoutInflater vi;
if (v == null) {
holder=new Holder();
vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.file_explorer_row, null);
holder.tt= (TextView) v.findViewById(R.id.file_explorer_tv_filename);
v.setTag(holder);
} else {
holder = (Holder) v.getTag();
}
String txt = objects.get(position); // Out of bounds happens here
if (!txt.equals("")) {
holder.tt.setText(txt);
}
return v;
}
static class Holder{
TextView tt;
}
}

Categories

Resources