Search code examples
javaandroidarraylisthashmapbaseadapter

Android BaseAdapter only shows correct information once


I'm trying to put together an adapter that will display the number of occurrences in a list. There are two ListViews in a tab host with each being in its own tab. As long as you do not click on the tab that shows the occurrences it will keep up with the data input just fine. The first time you go to view the listview, all of the groups are displayed with the correct amount of occurrences for each; however, from then on it does not want to update properly. At times it will not update at all, re-insert an existing group but still keep the old one.

For example, if I were to put in 10, 20, and 30 the first time I go to view the groups listview I would see:

10 -- 1
20 -- 1
30 -- 1

...but if I were to put in another 10 it would still display the same thing with no update. When I put something else in like 45 I get:

10 -- 1
20 -- 1
30 -- 1
10 -- 2

I can keep adding other numbers and it will just keep adding in 10 -- 1's or sometimes even more 20's or 30's. If I use debugAll() in the log window it will show that it attempts all of the numbers that I put in, and it will return the correct number of occurences, just the display won't keep up and is displaying more of what is already there.

I have tried putting in several log statements and they show that the information in the adapter is right, just the display is wrong.

import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;

public class HashAdapter extends BaseAdapter {
    private LinkedHashMap<String, String> mData = new LinkedHashMap<String, String>();
    private final ArrayList keyArray = new ArrayList();
    private final Context _context;

    public HashAdapter (Context context) {
        _context = context;
    }

    @Override
    public int getCount() {
        return keyArray.size();
    }

    @Override
    public String getItem(int position) {
        return mData.get(keyArray.get(position));
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View listView;
        final LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (convertView == null) { // FIXME
            listView = inflater.inflate(R.layout.list_item, null);
            TextView textView = (TextView) listView.findViewById(R.id.listItem);

            String tile = keyArray.get(position) + " -- " + getItem(position);
            textView.setText(tile);
            Log.i("getView Text Is", tile);
        } else {
            listView = convertView;
        }

        return listView;
    }

    public void addNewValue (String key) {
        if (mData.containsKey(key)) {
            int retrieve = Integer.parseInt(mData.get(key));
            mData.put(key, String.valueOf(++retrieve));
        } else { // HASH MAP CREATING A NEW KEY WITH VALUE OF 1
            mData.put(key, "1");
            keyArray.add(0, key);
        }
        this.notifyDataSetChanged();
        Log.i("Array List ", keyArray.toString());
    }

    public void modifyExistingValue (String oldValue, String newValue) {
        if (!oldValue.equals(newValue)) {
            int newInt = Integer.parseInt(mData.get(oldValue));
            if (newInt > 1) {
                mData.put(oldValue, String.valueOf(--newInt));
                String secondInt = mData.get(newValue);
                if (secondInt != null) {
                    int newNewInt = Integer.parseInt(secondInt);
                    mData.put(newValue, String.valueOf(++newNewInt));
                } else {
                    mData.put(newValue, "1");
                }
            } else {
                mData.remove(oldValue);
                keyArray.remove(oldValue);
                mData.put(newValue, "1");
                Log.i("Old Value ", oldValue + " Is Gone From HashMap");
            }
            keyArray.add(0, newValue);
        }
        this.notifyDataSetChanged();
        Log.i("Array List ", keyArray.toString());
    }

    public void removeOccurrence  (String oldValue) {
        String oldOccurrences = mData.get(oldValue);

        if (!oldOccurrences.equals("1")) { // IF THERE ARE ENOUGH REMAINING TO STILL EXIST
            int newInt = Integer.parseInt(oldOccurrences);
            mData.put(oldValue, String.valueOf(--newInt));
        } else { // NOT ENOUGH LEFT...REMOVE IT
            mData.remove(oldValue);
            keyArray.remove(oldValue);
            Log.i("Old Value", oldValue + " Is Gone From HashMap");
        }
        this.notifyDataSetChanged();
        Log.i("Array List ", keyArray.toString());
    }

    public void clear () {
        mData.clear();
        keyArray.clear();
        this.notifyDataSetChanged();
        Log.i("Array List ", keyArray.toString());
    }

    public void debugValue (String key) {
        Log.i("AdapterDebug Value", key + " has " + mData.get(key));
    }

    public void debugAll () {
        int size = keyArray.size();
        for (int i = 0; i < size; i++) {
            String retrieve = (String) keyArray.get(i);
            Log.i("AdapterDebug All", "Attempted " + retrieve + " and retrieved " + mData.get(retrieve));
        }
    }
}

EDIT:

I figured some one might find the fully working version useful so I'll put this here. It will keep track of re occurring values. Build off of it, use it as is, I don't care.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.LinkedHashMap;

/*
*       ARRAY ADAPTER FOR KEEPING TRACK OF REOCCURRING VALUES AND DISPLAYING ON A LISTVIEW
*       CREATED BY : COREY WILLIAMS
*       8/13/2014
*
*       BeerWare (http://en.wikipedia.org/wiki/Beerware)
* */

class HashAdapter extends BaseAdapter {
    private LinkedHashMap<String, String> mData = new LinkedHashMap<String, String>();
    private ArrayList keyArray = new ArrayList();
    private final Context _context;

    public HashAdapter (Context context) {
        _context = context;
    }

    @Override
    public int getCount() {
        return keyArray.size();
    }

    @Override
    public String getItem(int position) {
        return mData.get(keyArray.get(position));
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View listView;
        final LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if (convertView == null) {
            listView = inflater.inflate(R.layout.list_item, null);
            TextView textView = (TextView) listView.findViewById(R.id.listItem);

            String tile = keyArray.get(position) + " -- " + getItem(position);
            textView.setText(tile);
        } else {
            listView = convertView;
            TextView textView = (TextView) listView.findViewById(R.id.listItem);

            String tile = keyArray.get(position) + " -- " + getItem(position);
            textView.setText(tile);
        }

        return listView;
    }

    public void addNewValue (String key) {
        if (mData.containsKey(key)) {
            int retrieve = Integer.parseInt(mData.get(key));
            mData.put(key, String.valueOf(++retrieve));
        } else { // HASH MAP CREATING A NEW KEY WITH VALUE OF 1
            mData.put(key, "1");
            keyArray.add(0, key);
        }
        this.notifyDataSetChanged();
    }

    public void modifyExistingValue (String oldValue, String newValue) {
        if (!oldValue.equals(newValue)) {
            int oldAmmount = Integer.parseInt(mData.get(oldValue)); // GET HOW MANY ARE LEFT OF WHAT YOU SELECTED
            boolean alreadyHasNewValue = mData.containsKey(newValue);
            if (oldAmmount > 1) { // IF THERE IS SOME LEFT
                mData.put(oldValue, String.valueOf(--oldAmmount));
                if (alreadyHasNewValue) {
                    String secondInt = mData.get(newValue);
                    int newNewInt = Integer.parseInt(secondInt);
                    mData.put(newValue, String.valueOf(++newNewInt));
                } else {
                    mData.put(newValue, "1");
                }
            } else {
                mData.remove(oldValue);
                keyArray.remove(oldValue);
                if (alreadyHasNewValue) {
                    String secondInt = mData.get(newValue);
                    int newNewInt = Integer.parseInt(secondInt);
                    mData.put(newValue, String.valueOf(++newNewInt));
                } else {
                    mData.put(newValue, "1");
                }
            }
            if (!keyArray.contains(newValue)) {
                keyArray.add(0, newValue);
            }

        }
        this.notifyDataSetChanged();
    }

    public void removeOccurrence  (String oldValue) {
        String oldOccurrences = mData.get(oldValue);

        if (!oldOccurrences.equals("1")) { // IF THERE ARE ENOUGH REMAINING TO STILL EXIST
            int newInt = Integer.parseInt(oldOccurrences);
            mData.put(oldValue, String.valueOf(--newInt));
        } else { // NOT ENOUGH LEFT...REMOVE IT
            mData.remove(oldValue);
            keyArray.remove(oldValue);
        }
        this.notifyDataSetChanged();
    }

    public void clear () {
        mData.clear();
        keyArray.clear();
        this.notifyDataSetChanged();
    }

    public ArrayList getKeys () {
        return keyArray;
    }

    public void restoreKeys (ArrayList<String> restore) {
        keyArray = restore;
        this.notifyDataSetChanged();
    }

    public LinkedHashMap<String, String> getValues () {
        return mData;
    }

    public void restoreValues (LinkedHashMap<String, String> restore) {
        mData = restore;
        this.notifyDataSetChanged();
    }
}

Solution

  • In the "getView" method you must update the content placeholders (TextView(s) in your code) even if "convertView" is not null. It's because of view recycling system of ListView.

    So the updated code could be like this:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View listView;
        final LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
        if (convertView == null) {
            listView = inflater.inflate(R.layout.list_item, null);
        } else {
            listView = convertView;
        }
    
        TextView textView = (TextView) listView.findViewById(R.id.listItem);
    
        String tile = keyArray.get(position) + " -- " + getItem(position);
        textView.setText(tile);
        Log.i("getView Text Is", tile);
    
        return listView;
    }