Search code examples
javaandroidlistviewandroid-arrayadapter

Android ArrayAdapter does not update ListView


I have written a small implementation for a listview. Therefore I extended the ArrayAdapter class for my List rows and my objects.

public class MainActivity extends Activity implements NetplugListener {

    public static final int REFRESH_ID = 1;

    ListView listView;
    ArrayList<NetPlug> netplugs;
    NetplugArrayAdapter adapter;
    RemoteDataManager remoteManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        netplugs = new ArrayList<>();
        adapter = new NetplugArrayAdapter(this, netplugs);

        listView = new ListView(this);
        listView.setAdapter(adapter);
        setContentView(listView);

        remoteManager = new RemoteDataManager(this);
        remoteManager.registerNetplugListener(this);

    }

    @Override
    protected void onStart() {
        super.onStart();
        remoteManager.refresh();
    }



    @Override
    protected void onResume() {
        super.onResume();
        remoteManager.refresh();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        menu.add(0, REFRESH_ID, 0, "refresh");
        return true;

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
        case REFRESH_ID:
            remoteManager.refresh();
            break;
        }
        return true;

    }

    @Override
    public void onNewNetplugs(ArrayList<NetPlug> netplugs) {
        adapter.addAll(netplugs);
        adapter.notifyDataSetChanged();
    }

}

And here is the ArrayAdapter

public class NetplugArrayAdapter extends ArrayAdapter<NetPlug> {

    Context context;
    ArrayList<NetPlug> netplugs;
    Map<Integer,ViewHolder> viewholders;

    public NetplugArrayAdapter(Context context, ArrayList<NetPlug> netplugs) {
        super(context, R.layout.netplug_item);
        this.context = context;
        this.netplugs = netplugs;
        this.viewholders = new HashMap<>();
    }

    @Override
    public void add(NetPlug object) {
        this.netplugs.add(object);
        notifyDataSetChanged();
    }

    @Override
    public void addAll(Collection<? extends NetPlug> collection) {
        this.netplugs.addAll(collection);
        notifyDataSetChanged();
    }


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

        NetPlug n = netplugs.get(position);

        ViewHolder viewHolder;
        if(viewholders.get(position) != null) {

            viewHolder = viewholders.get(position);

        } else {

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.netplug_item, parent, false);

            viewHolder = new ViewHolder();
            viewHolder.labelView = (TextView) convertView.findViewById(R.id.label);
            viewHolder.valueView = (TextView) convertView.findViewById(R.id.value);

            viewholders.put(position, viewHolder);

        }

        viewHolder.labelView.setText(n.getName());
        viewHolder.valueView.setText(n.getIp());

        return convertView;

    }

    private static class ViewHolder {

        public TextView labelView;
        public TextView valueView;

    }

}

And my RemoteManager for filling the data

public class RemoteDataManager {

    RequestQueue queue;
    List<NetplugListener> listeners = new ArrayList<>();

    public RemoteDataManager(Context context) {
        queue = Volley.newRequestQueue(context);
    }

    public void refresh() {

        try {

            JSONObject json = new JSONObject();
            json.put("command", 0b1000);

            sendJson("http://192.168.0.120:7000", json);

        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    public void sendJson(String url, JSONObject json) {

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST,
                url, json, new ResponseListener(), new ResponseErrorListener());

        queue.add(request);

    }

    public void registerNetplugListener(NetplugListener listener) {
        this.listeners.add(listener);
    }

    private class ResponseListener implements Response.Listener<JSONObject> {

        @Override
        public void onResponse(JSONObject response) {

            try {

                if(response.getBoolean("success")) {

                    JSONArray array = response.getJSONArray("netplugs");

                    ArrayList<NetPlug> netplugs = new ArrayList<>();
                    for(int i = 0; i < array.length(); i++) {
                        netplugs.add(new NetPlug(array.getJSONObject(i)));
                    }

                    for(NetplugListener listener: listeners) {
                        listener.onNewNetplugs(netplugs);
                    }

                }

            } catch (Exception e) {
                Log.e(this.toString(), e.getMessage());
            }

        }

    }

    private class ResponseErrorListener implements Response.ErrorListener {

        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e(this.toString(), error.toString());
        }

    }

}

But there is no row populated on the display. And yes the Volley response hast one NetPlug as result.


Solution

  • Modify your constructor to call the super constructor with arguments:

    ArrayAdapter(Context context, int resource, List<T> objects)
    

    Also you don't need to override the add and addAll methods. The default implementation is just fine.

    Edit: To elaborate...
    When you call

     ArrayAdapter(Context context, int resource)
    

    the adapter creates an empty ArrayList for the objects. In your implementation of add and addAll you don't call the super so the default ArrayyList is always empty.