0

Before this, I used setAdapter with an update data but this reset the whole view and its current scroll location so I want to use notifyDataChanged. I followed these questions: BaseAdapter NotifyDatasetChanged() getView() Not Working and notifyDataSetChange not working from custom adapter. I didn't create a new instance of the arraylist but update it.
However it still doesn't work.


My base adapter:

public class ListViewAdapter extends BaseAdapter{
public ArrayList<HashMap<String, String>> list;
Activity activity;
TextView txtFirst;
TextView txtSecond;
TextView txtThird;
ImageView txtFourth;
public ListViewAdapter(Activity activity,ArrayList<HashMap<String, String>> list){
    super();
    this.activity=activity;
    this.list=list;
}

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

@Override
public Object getItem(int position) {
    return list.get(position);
}

@Override
public long getItemId(int position) {
    return position; //this was 0, I changed according to Vlad's suggestion
}

public void setNewList(ArrayList<HashMap<String, String>> list) {
    this.list.clear();
    this.list.addAll(list);
    notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater=activity.getLayoutInflater();
    if(convertView == null){
        convertView=inflater.inflate(R.layout.row, null);

        txtFirst=(TextView) convertView.findViewById(R.id.cellID);
        txtSecond = (TextView) convertView.findViewById(R.id.speedInfo);
        txtThird = (TextView) convertView.findViewById(R.id.gpsPointInfo);
        txtFourth=(ImageView) convertView.findViewById(R.id.status);
    }
    HashMap<String, String> map=list.get(position);
    txtFirst.setText(map.get(Constants.FIRST_COLUMN));
    txtSecond.setText(map.get(Constants.SECOND_COLUMN));
    txtThird.setText(map.get(Constants.THIRD_COLUMN));
    txtFourth.setImageResource(Integer.valueOf(map.get(Constants.FOURTH_COLUMN)));

    return convertView;
}


}

My class for creating and updating the listview has:

public class CellListViewTool {
    ArrayList<HashMap<String,String>> cellList;
    ListView cellListView;
    Activity mainActivity;
    ArrayList<QRCell> qrCells;
    ListViewAdapter adapter;

    public CellListViewTool(Activity mainActivity, ArrayList<QRCell> qrCells, ListView cellListView) {
        this.qrCells = qrCells;
        this.cellListView = cellListView;
        this.mainActivity = mainActivity;
        createCellListView();
    }

    private void createCellListView() {
        cellList = new ArrayList<>();

        for (QRCell qrCell : qrCells) {
            addRowToListView(qrCell, cellList);
        }
        mainActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                adapter = new ListViewAdapter(mainActivity, cellList);
                cellListView.setAdapter(adapter);
            }
        });

    }

    public synchronized void updateCellListView() {
        final ArrayList<HashMap<String, String>> newCellList = new ArrayList<>();

        for (QRCell QRCell : qrCells) {
            addRowToListView(QRCell, newCellList);
        }

        mainActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.d("HI", "run: refresh");
                adapter.setNewList(newCellList);
                Log.d("HI", "run: " + adapter.getItem(0).toString());
            }
        });
    }

    private void addRowToListView(QRCell qrCell, ArrayList<HashMap<String, String>> cellList) {
        String cellID = String.valueOf(qrCell.getCellID()),
                currentSpeed,
                currentPoints,
                targetSpeed = String.valueOf(qrCell.getTargetSpeed()),
                targetPoints = String.valueOf(qrCell.getTargetPoints());
        String speed;
        String points;
        if (qrCell.getStatus() != Constants.TestStatus.NOT_TESTED){
            currentSpeed = String.format("%.2f", qrCell.getMaxSpeed());
            currentPoints = String.valueOf(qrCell.getCurrentPoints());
        } else {
            currentSpeed = mainActivity.getString(R.string.not_active);
            currentPoints = mainActivity.getString(R.string.not_active);
        }
        speed = currentSpeed + "/ " + targetSpeed;
        points = currentPoints + "/ " + targetPoints;
        Constants.TestStatus status = qrCell.getStatus();

        HashMap<String, String> temp = new HashMap<>();
        temp.put(Constants.FIRST_COLUMN, "L" + cellID);
        temp.put(Constants.SECOND_COLUMN, speed);
        temp.put(Constants.THIRD_COLUMN, points);
        temp.put(Constants.FOURTH_COLUMN, String.valueOf(getStatusResID(status)));
        cellList.add(temp);
    }
    private int getStatusResID(Constants.TestStatus status) {
        switch (status) {
            case SUCCESS:
                return R.drawable.success_icon;
            case NOT_TESTED:
                return R.drawable.not_tested;
            case RUNNING:
                return R.drawable.running_icon;
            default:
                return R.drawable.failed_icon;
        }
    }
}

Can someone help me? Thank you.


UPDATE

I use ArrayAdapter but it still doesn't work. My ArrayAdapter class:

public class ListViewAdapter extends ArrayAdapter {

public ArrayList<HashMap<String, String>> list;
Activity activity;
TextView txtFirst;
TextView txtSecond;
TextView txtThird;
ImageView txtFourth;
public ListViewAdapter(Activity activity,ArrayList<HashMap<String, String>> list){
    super(activity, 0, list);
    this.activity=activity;
    this.list=list;
}

public void setNewList(ArrayList<HashMap<String, String>> list) {
    this.list.clear();
    this.list.addAll(list);
    notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater inflater=activity.getLayoutInflater();

    if(convertView == null){

        convertView=inflater.inflate(R.layout.row,null);

        txtFirst=(TextView) convertView.findViewById(R.id.cellID);
        txtSecond = (TextView) convertView.findViewById(R.id.speedInfo);
        txtThird = (TextView) convertView.findViewById(R.id.gpsPointInfo);
        txtFourth=(ImageView) convertView.findViewById(R.id.status);
    }

    HashMap<String, String> map=list.get(position);
    txtFirst.setText(map.get(Constants.FIRST_COLUMN));
    txtSecond.setText(map.get(Constants.SECOND_COLUMN));
    txtThird.setText(map.get(Constants.THIRD_COLUMN));
    txtFourth.setImageResource(Integer.valueOf(map.get(Constants.FOURTH_COLUMN)));

    return convertView;
}


}

In this method below, I log the first item of the adapter and it is updated. However I don't know why it doesn't update in the UI view...

public synchronized void updateCellListView() {
    final ArrayList<HashMap<String, String>> newCellList = new ArrayList<>();

    for (QRCell QRCell : qrCells) {
        addRowToListView(QRCell, newCellList);
    }

    mainActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Log.d("HI", "run: refresh");
            adapter.setNewList(newCellList);
            Log.d("HI", "run: " + adapter.getItem(0).toString());
        }
    });
}
Community
  • 1
  • 1
phuwin
  • 3,130
  • 4
  • 26
  • 49

2 Answers2

1

add a method inside your adapter class

public void setNewList(ArrayList<HashMap<String, String>> newList){
   this.list.clear();
   this.list.addAll(newList);
   notifyDataSetChanged()
}

then call this method from runOnUIThread.

public synchronized void updateCellListView() {
    final ArrayList<HashMap<String,String>> newCellList = new ArrayList<>();

    for (QRCell qrCell : qrCells) {
        addRowToListView(qrCell, newCellList);
    }

    mainActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            adapter.setNewList(newCellList);
        }
    });
}
Nishant Pardamwar
  • 1,450
  • 12
  • 16
1

In case you haven't heard about it, there's a new and much better replacement for ListViews called RecyclerView. Here's a tutorial https://developer.android.com/training/material/lists-cards.html

Might be worth looking into, we use it all the time.

headsvk
  • 2,726
  • 1
  • 19
  • 23
  • Eventhough this doesn't directly solve my problem, but I have successfully implemented the RecyclerView and it works so well. Thank you!!!! – phuwin Aug 31 '16 at 14:17
  • You're welcome. Seems like it wasn't too time consuming to switch to RecyclerView, good job. And a follow up question, you didn't know about RecyclerView? Where did you learn about ListView? The Android team should do a better job in updating the tutorials to show the current best practices. – headsvk Aug 31 '16 at 15:18
  • I only found a good tutorial. My senior which had previous experience about android (quite long time ago) told me to use ListView. – phuwin Aug 31 '16 at 20:34
  • Is the RecyclerView something for me? I have a Base adapter with no List/Array but Viewholders with Horizontal ListViews (making something looking like a spreadsheet that can be updated by complex AlertDialogs) handled by the public View getView(int position, View convertView, ViewGroup parent) that gets its data from a JNI-system. I have problems with the notifyDataSetChanged() called from the AlertDialog to the BaseAdapter (like suggested everywhere) but I have no list to update (as suggested everywhere). (And I think I remember that sometimes notifyDataSetChanged() works. I don't know why). – Jan Bergström Aug 15 '23 at 01:19