How to compare list items in custom adapter in Android - android

I have a custom adapter MyAdapter which displays items from a dynamic list(list2).. The list shows Area, location and there corresponding total items. there can be n number of similar area and location. I want to show a row "subtotal" which adds the corresponding total items of Similar Areas. Till now I'm able to show sorted items and "Total" items at end.
Now I want to display "subTotal" row after items of similar Area.
I don't know how do I compare each row till I get different Areas, in my Custom Adapter. Here's the code for my Adapter:
private class MyAdapter extends BaseAdapter {
private LayoutInflater inflater = null;
private ViewHolder holder = null;
#Override
public int getCount() {
// TODO Auto-generated method stub
if (!list2.isEmpty())
return list2.size();
else
return countItems.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
if (!list2.isEmpty())
return list2.get(position);
else
return countItems.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(final int position, View convertView,
final ViewGroup parent) {
// TODO Auto-generated method stub
if (convertView == null) {
holder = new ViewHolder();
inflater = (LayoutInflater) mActivity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(
R.layout.activity_search_group_row, null);
holder.text_area = (TextView) convertView
.findViewById(R.id.edtTxtRef);
holder.text_loc = (TextView) convertView
.findViewById(R.id.edtTxtName);
holder.text_total = (TextView) convertView
.findViewById(R.id.edtTxtPrice);
holder.total_lly = (LinearLayout) convertView
.findViewById(R.id.total_lly);
holder.txtSubTotal = (TextView) convertView
.findViewById(R.id.txtSubTotal);
holder.txtCount = (TextView) convertView
.findViewById(R.id.txtCount);
holder.txtCountTotal = (TextView) convertView
.findViewById(R.id.txtCountTotal);
holder.sum_lly = (LinearLayout) convertView
.findViewById(R.id.sum_lly);
holder.top_lly = (LinearLayout) convertView
.findViewById(R.id.top_lly);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
System.out.println("=====*********adapter*********======");
int total1 = 0;
if (!locList.isEmpty() && !areaList.isEmpty()) {
if (!list2.isEmpty()) {
if (list2.size() - 1 == position) {
for (int k = 0; k < countItems.size(); k++) {
total1 = total1 + countItems.get(k);
}
lastRow = true;
}
}
holder.text_area.setText(list2.get(position).getArea());
holder.text_loc.setText(list2.get(position).getLocation());
holder.text_total.setText(String.valueOf(countItems.get(position)));
} else {
searchList.setDivider(new ColorDrawable(
android.R.color.transparent));
searchList.setDividerHeight(0);
// when area and location spinners are null
if (locList.isEmpty() && areaList.isEmpty()) {
if (countItems.size() - 1 == position) {
for (int k = 0; k < countItems.size(); k++) {
total1 = total1 + countItems.get(k);
}
lastRow = true;
}
holder.top_lly.setVisibility(View.GONE);
}
}
if (lastRow) {
holder.sum_lly.setVisibility(View.VISIBLE);
holder.txtCountTotal.setText(String.valueOf(total1));
holder.txtCountTotal.setVisibility(View.VISIBLE);
lastRow = false;
}
return convertView;
}
private class ViewHolder {
TextView text_area, text_loc, text_total, txtSubTotal, txtCount,
txtCountTotal;
LinearLayout total_lly, sum_lly, top_lly;
}
}

You can have a POJO with attributes like area, location, and total. Then create a map of <String,List<YourPojo>> and populate it with area as the key and the List of POJO as value. Here you will get the values separated by area.
As an example, it will look like:
area1 -> [{area1,loc1,20},{area1,loc2,10}]
area2 -> [{area2,loc1,1},{area2,loc2,10}]
and so on.
In this way you will get different Lists for different keys.
Then iterate the keySet of the map and for every key show the value in different table rows.
Once display of one key is complete, create a row for subtotal for that particular key and then continue with the next key.
I hope this helps!

You must sort your list by a custom comparator!
http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
Create a class and implement the Comparator-Interface. Then you can define your own sorting-rules.
public class MyComparator implements Comparator<MyListObjectType> {
#Override
public int compare(MyListObjectType o1, MyListObjectType o2) {
if (o1.getTotal() > o2.getTotal()) {
return 1;
}
if (o1.getTotal() < o2.getTotal()) {
return -1;
}
if (o1.getTotal() == o2.getTotal()) {
return 0;
}
}
}
Use the comparator with:
Collections.sort( list, new MyComparator() );
An alternative is the implementation of the comparable-interface for your objects in your list.

You must have a list which contain unique Model object based on area and location so you must override equal and hashcode method
let it is your model
class Model {
String area;
String location;
int count;
Model(String area,String location) {
this.area = area;
this.location = location;
}
public String getLocation() {
return location;
}
public String getArea() {
return area;
}
#Override
public boolean equals(Object o) {
if (o == this) {
count = 1;
return true;
} else if (o instanceof Model) {
Model t = (Model) o;
if (t.getArea().equalsIgnoreCase(getArea()) && t.getLocation().equalsIgnoreCase(getLocation())) {
count++;
return true;
}
}
return false;
}
public int getCount() {
return count;
}
#Override
public int hashCode() {
return super.hashCode();
}
}
For Example modelList hold the data
use list to show data it will hold unique data based on area and location and also have total count pass it to adapter
ArrayList<Model> model = new ArrayList(); //you have all data with same area and location
ArrayList<Model> list = new ArrayList(); //it will hold total area with same area + location
for(int i=0;i<model.size()-1;i++){
Model t = model.get(i);
for(int j=i+1;j<model.size();j++){
Model m = model.get(j);
if(!t.equals(m)){
list.add(t);
}else{
if(!list.contains(t)){
list.add(t);
}
}
}
}

Related

How to set visibility if data is present in the arraylist

I want to check whether the particular row of data is present or not in database. If data is present then set visibility mode is visible and display my first image if data is not present in database then set visibility is Invisible and display my second image.
Here is my code.
public class ListViewAdapter extends BaseAdapter {
Context context;
LayoutInflater inflater;
ArrayList<Product> AllMenu = new ArrayList<>();
ImageLoader imageLoader;
SQLiteDatabase sqLite;
public ListViewAdapter(Context context, ArrayList<Product> itemlist) {
this.context=context;
AllMenu = itemlist;
imageLoader = new ImageLoader(context);
}
public int getCount() {
return AllMenu.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(final int position, final View convertView, ViewGroup parent) {
// Declare Variables
Product tempMenu = AllMenu.get(position);
ImageView image_path,facility1,facility_1;
TextView name,location,desc,facility2,facility3,facility4;
ListView listView;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View view = inflater.inflate(R.layout.viewpage, parent, false);
// Get the position
//listView = (ListView) view.findViewById(R.id.myimagelist);
name = (TextView) view.findViewById(R.id.fh_name);
location = (TextView) view.findViewById(R.id.fh_loc);
desc = (TextView) view.findViewById(R.id.fh_desc);
facility1 = (ImageView) view.findViewById(R.id.fh_fc1);
facility_1 = (ImageView) view.findViewById(R.id.fh_fc11);
image_path = (ImageView) view.findViewById(R.id.image_all_main);
name.setText(tempMenu.getName());
location.setText(tempMenu.getLocation());
desc.setText(tempMenu.getDescription());
for(Product myPoint : AllMenu) {
if(myPoint.getFacility1() != null && myPoint.getFacility1().contains("Pool")) {
facility1.setVisibility(view.VISIBLE);
facility_1.setVisibility(view.INVISIBLE);
}else {
facility_1.setVisibility(view.VISIBLE);
facility1.setVisibility(view.INVISIBLE);
}
}
imageLoader.DisplayImage(tempMenu.getImage_path(),image_path);
return view;
}}
All data should come from server. Please help me solve this problem. Thank You
I want to compare with my string here is "Pool" is my string in above code.
If given string == pool then set Visibile or else set Invisible.
I want to make my changes here only.
for(Product myPoint : AllMenu) {
if(myPoint.getFacility1() != null && myPoint.getFacility1().contains("Pool")) {
facility1.setVisibility(view.VISIBLE);
facility_1.setVisibility(view.INVISIBLE);
}else {
facility_1.setVisibility(view.VISIBLE);
facility1.setVisibility(view.INVISIBLE);
}
}
Use log in your code to make sure that your comparing code working and also use equalsIgnoreCase like #shark says. Like this:
for(Product myPoint : AllMenu) {
Log.d("LIST_VIEW_ADAPTER", myPoint.getFacility1());
if(myPoint.getFacility1() != null && myPoint.getFacility1().equalsIgnoreCase("Pool")) {
facility1.setVisibility(view.VISIBLE);
facility_1.setVisibility(view.INVISIBLE);
Log.d("LIST_VIEW_ADAPTER", "facility1 contains Pool");
}else {
facility_1.setVisibility(view.VISIBLE);
facility1.setVisibility(view.INVISIBLE);
Log.d("LIST_VIEW_ADAPTER", "facility1 no Pool!");
}
}
Check log result in android monitor and make sure that it always return "facility1 contains Pool" for the right set visibility.
I prefer to split checking 'null' value in it's own if, like this:
for(Product myPoint : AllMenu) {
Log.d("LIST_VIEW_ADAPTER", myPoint.getFacility1());
if(myPoint.getFacility1() != null) {
if(myPoint.getFacility1().equalsIgnoreCase("Pool")) {
facility1.setVisibility(view.VISIBLE);
facility_1.setVisibility(view.INVISIBLE);
Log.d("LIST_VIEW_ADAPTER", "facility1 contains Pool");
} else {
facility_1.setVisibility(view.VISIBLE);
facility1.setVisibility(view.INVISIBLE);
Log.d("LIST_VIEW_ADAPTER", "facility1 no Pool!");
}
} else {
// do something if null here.
Log.d("LIST_VIEW_ADAPTER", "NULL Value!");
}
}
-- UPDATE --
You should return position value in your following code:
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
To :
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}

Android BaseAdapter's getCount() getView()

I have a BaseAdapter with 3 kind of layout which is used to put JSONObject to my ListView. The adapter getCount() returns correct number of items that should be displayed on the ListView, but it only display the first one.
I tried to find another response to this problem here, but i've found none.
This is my code:
public class PerfilInfoAdapter extends BaseAdapter {
public static final int VIEW_TYPE_TITULO = 0;
public static final int VIEW_TYPE_DESCRICAO = 1;
public static final int VIEW_TYPE_KEY_VALUE = 2;
private JSONArray list;
private Activity activity;
private ViewHolder viewHolder;
public PerfilInfoAdapter(Activity activity, JSONArray list) {
this.activity = activity;
this.list = list;
}
protected class ViewHolder {
TextView textViewTitulo;
TextView textViewDescricao;
TextView textViewKey;
TextView textViewValue;
}
#Override
public int getCount() {
Log.d("PerfilInfoAdapter", "Number of items in array: " + Integer.toString(this.list.length()));
return this.list.length();
}
#Override
public JSONObject getItem(int position) {
JSONObject json = null;
try {
json = this.list.getJSONObject(position);
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
int retorno = -1;
JSONObject json = null;
try {
json = this.list.getJSONObject(position);
if (json.getString("key").equals("Titulo")) {
retorno = VIEW_TYPE_TITULO;
} else if (json.getString("key").equals("Descrição")
|| json.getString("key").equals("Sou")) {
retorno = VIEW_TYPE_DESCRICAO;
} else {
retorno = VIEW_TYPE_KEY_VALUE;
}
} catch (JSONException e) {
e.printStackTrace();
}
return retorno;
}
#Override
public int getViewTypeCount() {
return 3;
}
#Override
public View getView(int position, View container, ViewGroup viewGroup) {
System.out.println("getView " + position + " " + container);
this.viewHolder = null;
int type = this.getItemViewType(position);
if (container == null) {
this.viewHolder = new ViewHolder();
switch (type) {
case VIEW_TYPE_TITULO:
container = this.activity.getLayoutInflater().inflate(
R.layout.perfil_info_full_titulo, viewGroup, false);
this.viewHolder.textViewTitulo = (TextView) container
.findViewById(R.id.perfil_info_full_textViewTitulo);
break;
case VIEW_TYPE_DESCRICAO:
container = this.activity.getLayoutInflater().inflate(
R.layout.perfil_info_full_descricao, viewGroup, false);
this.viewHolder.textViewDescricao = (TextView) container
.findViewById(R.id.perfil_info_full_textVewDescricao);
break;
case VIEW_TYPE_KEY_VALUE:
container = this.activity.getLayoutInflater().inflate(
R.layout.perfil_info_list, viewGroup, false);
this.viewHolder.textViewKey = (TextView) container
.findViewById(R.id.perfil_info_full_chave_valor_textFieldChave);
this.viewHolder.textViewValue = (TextView) container
.findViewById(R.id.perfil_info_full_chave_valor_textFieldValor);
break;
}
container.setTag(this.viewHolder);
} else {
this.viewHolder = (ViewHolder)container.getTag();
}
try {
JSONObject json = this.list.getJSONObject(position);
switch (type) {
case VIEW_TYPE_TITULO:
this.viewHolder.textViewTitulo.setText(json.getString("value"));
break;
case VIEW_TYPE_DESCRICAO:
this.viewHolder.textViewDescricao.setText(json
.getString("value"));
break;
case VIEW_TYPE_KEY_VALUE:
this.viewHolder.textViewKey.setText(json.getString("key"));
this.viewHolder.textViewValue.setText(json.getString("value"));
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
return container;
}
}
This is what my log returns:
10-26 09:42:30.568: D/PerfilInfoAdapter(17228): Number of items in
array: 11
Another important information is that my ListView is inside another GridView, which has 4 different kinds of views, the gridView is working perfectly, but not the ListView.
public class PerfilAdapter extends BaseAdapter {
private List<JSONObject> jsonList;
private Activity activity;
private PerfilHelper helper;
private ImageLoader imageLoader;
private ViewHolder viewHolder;
private boolean exibirFull;
public static final int VIEW_TYPE_FOTO_PRINCIPAL = 0;
public static final int VIEW_TYPE_INFO = 1;
public static final int VIEW_TYPE_INFO_LIST = 2;
public static final int VIEW_TYPE_GALERIA = 3;
public PerfilAdapter(Activity activity, List<JSONObject> json, PerfilHelper helper) {
this.activity = activity;
this.helper = helper;
this.jsonList = json;
this.exibirFull = true;
if (!ImageLoader.getInstance().isInited()) {
ImageLoader.getInstance().init(new ImageLoaderConfiguration.Builder(this.activity).build());
}
imageLoader = ImageLoader.getInstance();
}
public void exibirFull(boolean exibir) {
this.exibirFull = exibir;
this.notifyDataSetChanged();
}
#Override
public int getCount() {
return this.jsonList.size();
}
#Override
public Object getItem(int i) {
return this.jsonList.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public int getItemViewType(int position) {
int retorno = -1;
if (this.jsonList.get(0).has("foto")) {
if (position == 0) {
retorno = VIEW_TYPE_FOTO_PRINCIPAL;
}
else if (position == 1) {
retorno = VIEW_TYPE_INFO;
}
else if (position == 2) {
if (this.exibirFull) {
retorno = VIEW_TYPE_INFO_LIST;
}
else {
retorno = VIEW_TYPE_GALERIA;
}
}
else {
retorno = VIEW_TYPE_GALERIA;
}
}
else {
if (position == 0) {
retorno = VIEW_TYPE_INFO;
}
else if (position == 1) {
if (this.exibirFull) {
retorno = VIEW_TYPE_INFO_LIST;
}
else {
retorno = VIEW_TYPE_GALERIA;
}
}
else {
retorno = VIEW_TYPE_GALERIA;
}
}
return retorno;
}
#Override
public int getViewTypeCount() {
return 4;
}
public void updateJsonPerfil(List<JSONObject> json) {
this.jsonList = json;
this.notifyDataSetChanged();
}
#Override
public View getView(int i, View container, ViewGroup viewGroup) {
this.viewHolder = null;
int type = this.getItemViewType(i);
if (container == null) {
this.viewHolder = new ViewHolder();
switch (type) {
case VIEW_TYPE_FOTO_PRINCIPAL:
container = this.activity.getLayoutInflater().inflate(R.layout.perfil_foto, viewGroup, false);
this.viewHolder.imageView = (ImageView) container.findViewById(R.id.perfil_foto_imageView);
break;
case VIEW_TYPE_INFO:
container = this.activity.getLayoutInflater().inflate(R.layout.perfil_info, viewGroup, false);
this.viewHolder.textViewApelido = (TextView) container.findViewById(R.id.perfil_info_apelido);
this.viewHolder.textViewCidade = (TextView) container.findViewById(R.id.perfil_info_textVewCidade);
this.viewHolder.textViewDistancia = (TextView) container.findViewById(R.id.perfil_info_textViewDistancia);
break;
case VIEW_TYPE_INFO_LIST:
container = this.activity.getLayoutInflater().inflate(R.layout.perfil_info_list, viewGroup, false);
this.viewHolder.listViewInfo = (ListView) container.findViewById(R.id.perfil_info_list_listView);
break;
case VIEW_TYPE_GALERIA:
container = this.activity.getLayoutInflater().inflate(R.layout.perfil_info, viewGroup, false);
break;
}
container.setTag(this.viewHolder);
}
else {
this.viewHolder = (ViewHolder)container.getTag();
}
if (this.jsonList.size() > 0) {
JSONObject json = this.jsonList.get(i);
try {
if (type == VIEW_TYPE_FOTO_PRINCIPAL) {
JSONObject foto = json.getJSONObject("foto");
this.imageLoader.displayImage(foto.getString("full"), this.viewHolder.imageView);
}
else if (type == VIEW_TYPE_INFO) {
JSONObject perfil = json.getJSONObject("perfil");
this.viewHolder.textViewApelido.setText(perfil.getString("apelido"));
this.viewHolder.textViewCidade.setText(perfil.getString("cidade"));
this.viewHolder.textViewDistancia.setText(perfil.getString("distancia"));
}
else if (type == VIEW_TYPE_INFO_LIST) {
// This is where i use the second ListView
this.viewHolder.listViewInfo.setAdapter(new PerfilInfoAdapter(this.activity, json.getJSONArray("info")));
}
else {
Log.d("PerfilAdapter", "Populando: VIEW_TYPE_GALERIA");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return container;
}
protected class ViewHolder {
ImageView imageView;
TextView textViewApelido;
TextView textViewCidade;
TextView textViewDistancia;
ListView listViewInfo;
}
}
I have tried changing the ListView to a GridView, but the problem is with the adapter.
Can anybody help me? I would appreciate it!
Your first problem: Trying to combine a ListView and a GridView. Never ever ever put one within the other. You'll have all sorts of problems...as you are noticing. The first big problem is scrolling. Android does not like it when a scrollable view is embedded within another and both scroll the same direction. Comical sketch from Android employee about this. Doing so is only viable when one scrolls horizontally and the other vertically.
Your next big problem, embedding a ListAdapter within another ListAdapter. You have to remember, that the getView() method can be invoked 3-4 times per position. When you embed another adapter for each position which itself will be invoked 3-4 times per it's own position...holy performance hit! This has bad idea written all over it.
A concern I see is your JSONArray/List referencing. The PerfilInfoAdapter maintains the same reference to the JSONArray used to instantiate it...which is the same data referenced by the PerfilAdapter List. Further the PerfilAdapter maintains the same list referenced by whomever is using it. This sets up a dangerous chain of references that can cause issues when modifying if you are not careful. Ideally, each adapter should maintain the same data in its on List or JSONArray instance.
To sum up, the answer is to change your design choice. There are other ways to display data other then needing vertical scrolling within vertical scrolling. If the ListView doesn't need scrolling use a LinearLayout. If the GridView doesn't need scrolling use a TableLayout or GridLayout. Or just completely change the UX by coming up with a different UI.
As a side note, if you need a full fledged JSONArray adapter check out Advanced-Adapters. The JSONAdapter is releasing within a week or so and can be found on the Redesign branch. Its code complete, just the demo app that's holding up the release.
How about implement getItem correctly (not return null)?
or I prefer
make POJO class and convert JSON into it. (like using GSON)
extends ArrayAdapter instead of BaseAdapter so that u don't have to implements all abstract methods.

Making Adapter for a list with some null values

I got a list, that i would like to show in a ListView, using my own custom adapter. So this list have some null values in it, and also some "important" not-null values.
It could be like this:
(N representing Null)
(D representint some valuable data)
myList:
[N,N,D,D,N,N,D,N,D,N,N] for example.
So i got my adapter, but i cannot handle the null values in the list.
This is my adapter:
public class ItemAdapter extends ArrayAdapter {
List<Item> itemList;
private Activity act;
boolean selling;
public ItemAdapter(Activity act, List<Item> itemList, boolean selling) {
super(act, R.layout.item_view_layout, itemList);
this.itemList = itemList;
this.act = act;
this.selling = selling;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final Item itemManipulated = itemList.get(position);
if (convertView == null) {
convertView = new ItemInShopView(act, itemManipulated);
holder = new ViewHolder();
holder.convertView = convertView;
holder.itemNameTextView = (TextView) ((ItemView) convertView).getItemNameTextView();
holder.iconImageView = (ImageView) ((ItemView) convertView).getItemIconImageView();
holder.coinView = (CoinView) ((ItemInShopView) convertView).getCoinView();
holder.coinView.init(act);
holder.itemRarityHidedTextView = (TextView) ((ItemView) convertView).getItemRarityHidedTextView();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.itemNameTextView.setText(itemManipulated.getName());
holder.iconImageView.setImageResource(itemManipulated.getIcon());
holder.itemRarityHidedTextView.setText(itemManipulated.getRarity());
Colorer.setTextViewColorByItemRarity(holder.itemNameTextView, holder.getRarity(), act);
if (selling) {
holder.coinView.setCoins(itemManipulated.getSellPrice());
} else {
holder.coinView.setCoins(itemManipulated.getPrice());
}
holder.convertView.setOnClickListener(new OnClickListenerWithPreventDoubleTapper(itemManipulated));
holder.convertView.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false;
}
});
return convertView;
}
class OnClickListenerWithPreventDoubleTapper extends OnClickListenerWithPreventDoubleTap {
Item item;
public OnClickListenerWithPreventDoubleTapper(Item item) {
this.item = item;
}
#Override
protected void performAction() {
new ItemDialog(act, item).show();
}
}
static class ViewHolder {
TextView itemRarityHidedTextView;
TextView itemNameTextView;
ImageView iconImageView;
CoinView coinView;
View convertView;
public String getRarity() {
return itemRarityHidedTextView.getText().toString();
}
}
}
How could i implement some way to get the adapter handle null values and shows nothing there, or maybe show a dummy layout with nothing on it?
I couldnt make a new list without null values and pass these new list to the adapter, because the nulls have an important meaning in an other view.
I hope my problem is clear. Please help if you can.
Why not just?
if (itemManipulated != null){
holder.itemNameTextView.setText(itemManipulated.getName());
holder.iconImageView.setImageResource(itemManipulated.getIcon());
holder.itemRarityHidedTextView.setText(itemManipulated.getRarity());
Colorer.setTextViewColorByItemRarity(holder.itemNameTextView, holder.getRarity(),act);
if (selling) {
holder.coinView.setCoins(itemManipulated.getSellPrice());
} else {
holder.coinView.setCoins(itemManipulated.getPrice());
}
} else {
holder.itemNameTextView.setText("No Item");
... (whatever default values you like)
}
Edit:
If you don't want to display nulls at all you will need to do something more complex.
in getView: find the nth piece of actual data
in getCount: return the number of pieces of actual data
getView:
int posInArray = -1;
for (int i =0; i <= position; i++){
posInArray++;
while(itemList.get(posInArray) == null){
posInArray++;
}
}
itemManipulated = itemList.get(posInArray);
...
getCount:
int count = 0;
for(int i = 0; i < itemList.size(); i++){
if (itemList.get(i) != null){
count++;
}
}
return count;

custom adapter filter get wrong position id

So I have a custom adapter, which I tries to implement a filter search where user key search item from edittext. And the filtering works just fine. However, in my list, I do also implement checkbox.
Let's say I have a list
Bar
Tar
Foo
Kay
Default list would get the position correctly, so no issue here.
The issue starts when I search for say a and the list will becomes.
Bar
Tar
Kay
And if I check on Kay after search, it returns me Foo instead.
And the following is my code for my adapter and filter, what is wrong?
public class MyMediaAdapter extends ArrayAdapter<Media> implements Filterable {
private List<Media> list;
private final Activity context;
private Filter mediaFilter;
private List<Media> origMediaList;
public MyMediaAdapter(Activity context, List<Media> list) {
super(context, R.layout.media_view, list);
this.context = context;
this.list = list;
this.origMediaList = list;
}
public int getCount() {
return list.size();
}
public Media getItem(int position) {
return list.get(position);
}
public long getItemId(int position) {
return list.get(position).hashCode();
}
private class ViewHolder {
protected TextView fName, fSub, fDuration, fSize;
protected CheckBox checkbox;
// protected CheckBox checkbox1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
// Moved here to ensure the checkbox is persistent
ViewHolder viewHolder = new ViewHolder();
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.media_view, null);
// Moved out of the if-else to solve the problem
// view being recycled each time it scrolls
// final ViewHolder viewHolder = new ViewHolder();
viewHolder.fName = (TextView) view.findViewById(R.id.tvfname);
viewHolder.fSub = (TextView) view.findViewById(R.id.tvsub);
viewHolder.fDuration = (TextView) view.findViewById(R.id.tvduration);
viewHolder.fSize = (TextView) view.findViewById(R.id.tvsize);
viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check);
view.setTag(viewHolder);
// Moved out of the if-else to solve the problem
// view being recycled each time it scrolls
// viewHolder.checkbox.setTag(list.get(position));
} else {
view = convertView;
// Moved out of the if-else to solve the problem
// view being recycled each time it scrolls
// ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
viewHolder = (ViewHolder) view.getTag();
}
// Moved here to ensure the checkbox is persistent
viewHolder.checkbox.setId(position);
viewHolder.checkbox.setTag(list.get(position));
ViewHolder holder = (ViewHolder) view.getTag();
holder.fName.setText(list.get(position).getName());
holder.fSub.setText(list.get(position).getPath());
// Converting duration from String to Long
long milli = Long.valueOf(list.get(position).getDuration());
// Put it in % min, % sec format to display
holder.fDuration.setText(util.readableTime(milli));
// Convert data size from String to Long
long datasize = Long.valueOf(list.get(position).getData());
// Put in human readable format
holder.fSize.setText(util.readableFileSize(datasize));
holder.checkbox.setChecked(list.get(position).isSelected());
// viewHolder.checkbox.setId(position);
viewHolder.checkbox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
CheckBox cb = (CheckBox) v;
int id = cb.getId();
if (selection[id]) {
cb.setChecked(false);
selection[id] = false;
list.get(id).setSelected(false);
} else {
cb.setChecked(true);
selection[id] = true;
list.get(id).setSelected(true);
}
}
});
// Implement SelectAll/DeselectAll feature
final CheckBox checkbox1 = (CheckBox) findViewById(R.id.cb_selectall);
checkbox1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton button, boolean checked) {
// TODO Auto-generated method stub
if (checked) {
checkbox1.setText("Click to Deselect All");
for (int i = 0; i < list.size(); i++) {
selection[i] = true;
list.get(i).setSelected(true);
}
// Called to notify checkbox changes so the view gets updated immediately
notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "All files are selected", Toast.LENGTH_LONG).show();
} else {
checkbox1.setText("Click to Select All");
for (int i = 0; i < list.size(); i++) {
selection[i] = false;
list.get(i).setSelected(false);
}
notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "All files are deselected", Toast.LENGTH_LONG).show();
}
}
});
return view;
}
public void resetData() {
list = origMediaList;
}
#Override
public Filter getFilter() {
if (mediaFilter == null)
mediaFilter = new mediaFilter();
return mediaFilter;
}
private class mediaFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// We implement here the filter logic
if (constraint == null || constraint.length() == 0) {
// No filter implemented we return all the list
results.values = origMediaList;
results.count = origMediaList.size();
}
else {
// We perform filtering operation
List<Media> nMediaList = new ArrayList<Media>();
for (Media m : list) {
if (m.getName().toUpperCase().contains(constraint.toString().toUpperCase()))
nMediaList.add(m);
}
results.values = nMediaList;
results.count = nMediaList.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
list = (List<Media>) results.values;
notifyDataSetChanged();
}
}
}
}
I have the following setup so I know which has been selected.
private boolean[] selection;
private int count;
// After I fetch my list
count = getMediaList.size();
selection = new boolean[count];
// Inside onOptionsItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
final ArrayList<Integer> posSel = new ArrayList<Integer>();
posSel.clear();
storeSelectedMedia.clear();
/*
* Construct the list of selected items
*/
boolean noSelect = false;
//Log.i("MediaSelection", "" + selection.length);
for (int i = 0; i < selection.length; i++) {
//Log.i("MediaSelect", "" + getMediaList.get(i).isSelected());
if (selection[i] == true) {
//if (getMediaList.get(i).isSelected() == true) {
noSelect = true;
Log.e("Mediasel pos thu-->", "" + i);
posSel.add(i);
storeSelectedMedia.add(getMediaList.get(i).getPath());
}
}
switch (item.getItemId()) {
case R.id.action_sfd:
if (noSelect) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final ScrollView s_view = new ScrollView(getApplicationContext());
final TextView t_view = new TextView(getApplicationContext());
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("\n Name: \t " + getMediaList.get(posSel.get(0)).getName());
sBuilder.append("\n Parent: \t " + getMediaList.get(posSel.get(0)).getParent());
sBuilder.append("\n Type: \t " + getMediaList.get(posSel.get(0)).getType());
sBuilder.append("\n Size: \t\t " + util.readableFileSize(getMediaList.get(posSel.get(0)).getSize()));
sBuilder.append("\n ");
t_view.setText(sBuilder);
t_view.setTextSize(14);
s_view.addView(t_view);
builder.setTitle("File Properties")
.setView(s_view);
AlertDialog dialog = builder.create();
dialog.show();
Toast.makeText(this,
"Selected Items:" + storeSelectedMedia.toString(),
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this,
"No files selected",
Toast.LENGTH_SHORT).show();
}
break;
Hopefully that would be enough information.
Anyone has any idea on this? Appreciate it greatly!
I have solved my own problem. As I was using getMediaList to get the item to display, I forgotten that I have no update my getMediaList to the "after-filtered" list.
Thus, on the publishResult method, before notifyDataSetChanged();, I basically just assign the getMediaList = list.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Now we have to inform the adapter about the new list filtered
if (results.count == 0)
notifyDataSetInvalidated();
else {
list = (List<Media>) results.values;
// HERE
getMediaList = list;
notifyDataSetChanged();
}
}
Checked through it for quite a long time before I realize this stupid mistake. Hope it helps someone in the future.

Android Listview item duplication

I have got a listview which uses a special adapter to pass data into the listview from the database.But the problem is that I am only getting one listview item being repeated and the other details are not being displayed. When I put breakpoints and debug the project, all the details are being passed to the hashmap, but the listview is only showing one particular item repeatedly. The code is shown below:
static class ViewHolder {
TextView txtmername,txtmerid,txtmeradd,txtmermeasure;
Button btnselect;
}
private LayoutInflater mInflater;
public SpecialAdapter(Context ctx,List<HashMap<String, String>> listData, int resourceId, String[] columnTags, int[] columnIds) {
super(ctx, listData, resourceId, columnTags, columnIds);
ctx=MerchantList.this;
listData=listData;
resourceId=R.layout.merchant_listview;
columnTags=columnTags;
columnIds=columnIds;
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return super.getItem(position);
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
ViewHolder holder;
Context con=getApplicationContext();
if(convertView==null)
// convertView = getActivity().getLayoutInflater().inflate(R.layout.stores_listview_layout, pa
mInflater = (LayoutInflater)con.getSystemService(con.LAYOUT_INFLATER_SERVICE);
convertView=mInflater.inflate(R.layout.merchantlistview, null);
holder = new ViewHolder();
holder.txtmername = (TextView) convertView.findViewById(R.id.lblMerchantName);
holder.txtmeradd=(TextView)convertView.findViewById(R.id.lblAddress);
holder.txtmerid=(TextView)convertView.findViewById(R.id.lblMerchantId);
holder.txtmermeasure=(TextView)convertView.findViewById(R.id.lblMeasure);
holder.btnselect=(Button)convertView.findViewById(R.id.btnSelect);
holder.btnselect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
});
convertView.setTag(holder);
if(convertView !=null)
{
holder=(ViewHolder)convertView.getTag();
// Binding the data efficiently with the holder
SQLiteDatabase db=openOrCreateDatabase("NEW.db", MODE_PRIVATE, null);
Cursor OrderCursor = db.rawQuery("SELECT DISTINCT(A.ID), B.NAME, B.ADDRESS, A.MEASURE FROM (SELECT ID, MIN( CAST(STOCK_IN_HAND AS REAL) /REORDER_LEVEL) AS MEASURE FROM INVENTORY GROUP BY ID) A INNER JOIN MASTER B ON A.ID=B.ID ORDER BY A.MEASURE", null);
listData.clear();
if(OrderCursor!= null)
{
if(OrderCursor.moveToFirst()){
for (int i = 0; i < OrderCursor.getCount(); i++){
// String first,second,third,fourth=null;
HashMap<String,String> map = new HashMap<String, String>();
map.put(columnTags[0], OrderCursor.getString(OrderCursor.getColumnIndex("NAME")));
map.put(columnTags[1], OrderCursor.getString(OrderCursor.getColumnIndex("ADDRESS")));
map.put(columnTags[2], OrderCursor.getString(OrderCursor.getColumnIndex("ID")));
map.put(columnTags[3], OrderCursor.getString(OrderCursor.getColumnIndex("MEASURE")));
listData.add(map);
String measure = map.get("measure").toString();
String name=map.get("Name").toString();
String address=map.get("Address").toString();
String id=map.get("Id").toString();
holder.txtmerchantname.setText(name);
holder.txtmeradd.setText(address);
holder.txtmerid.setText(id);
holder.txtmermeasure.setText(measure);
double measure1=Double.parseDouble(measure);
if(measure1 > 1.5)
{
convertView.setBackgroundColor(getResources().getColor(R.color.Green));
}
else if((1.5 >= measure1 ) && (measure1>1.0))
{
convertView.setBackgroundColor(getResources().getColor(R.color.Yellow));
}
else if(1.0>=measure1)
{
convertView.setBackgroundColor(Color.RED);
}
OrderCursor.moveToNext();
}//end of for
}
OrderCursor.close();
db.close();
}
}
return convertView;
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
#Override
public int getViewTypeCount() {
return super.getViewTypeCount();
}
}
Try using the following code which i guess will be helpful. Hence you are using the hashmap the arrayAdapter can be used.
https://stackoverflow.com/a/15061779/2106338
getViewTypeCount() is not matched with your listView items count therefore it adds up another item.
In your case I think its about the measure condition you are using.
In the end you should use else instead of else if
OR
if there is another condition, you must treat it.

Categories

Resources