0

I'm trying to refresh my ListView whenever I delete an item on it. But setting a notifyDataSetChanged(); is giving me this error:

Cannot refer to a non-final variable adapter inside an inner class defined in a different method.

The method notifyDataSetChanged() is undefined for the type ListAdapter.

ArrayList <HashMap <String, String> > data = dataHolder.getAllData();
dataHolder.getAllData();

if(data.size() !=0){

ListView lv = (ListView) findViewById(R.id.datalist);
ListAdapter adapter = new SimpleAdapter(MainActivity.this, data, R.layout.dataentry, new String[]{"unique_id","lastName"}, new int[]{R.id.unique_id,R.id.last_name});
lv.setAdapter(adapter);
lv.setOnItemLongClickListener(new OnItemLongClickListener() {

                @Override
                public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                        int arg2, long arg3) {

                    AlertDialog.Builder adb = new AlertDialog.Builder(MainActivity.this);
                    adb.setTitle("Delete?");
                    adb.setIcon(android.R.drawable.ic_dialog_alert);
                    adb.setMessage("Delete selected item?");
                    adb.setCancelable(false);
                    adb.setNegativeButton("Cancel", null);
                    adb.setPositiveButton("Delete", new AlertDialog.OnClickListener() {

                    public void onClick(DialogInterface dialog, int which) {

                        TextView uID = (TextView) findViewById(R.id.unique_id);
                        String unique_id = uID.getText().toString();
                        dataHolder.deleteData(unique_id);
                        adapter.notifyDataSetChanged();
                    }
                });  
                adb.show();
                return false;
                }
            });
}

Then it suggests to change it to:

((BaseAdapter) adapter).notifyDataSetChanged();

final ListAdapter adapter = new SimpleAdapter(MainActivity.this, data, R.layout.dataentry, new String[]{"unique_id","lastName"}, new int[]{R.id.unique_id,R.id.last_name});

But it's not refreshing the list after changing to that. What is the solution for this?

luwionline
  • 186
  • 2
  • 12

4 Answers4

3

To reference adapter from within the AlertDialog.OnClickListener, you need it to be final (that's basically what the error tells you). So just declare it final:

final BaseAdapter adapter = new SimpleAdapter(MainActivity.this, data, R.layout.dataentry, new String[]{"unique_id","lastName"}, new int[]{R.id.unique_id,R.id.last_name});

You could also just grab it from the parameters you are called with:

@Override
public boolean onItemLongClick(final AdapterView<?> adapterView, View arg1, int arg2, long arg3) {
    // ...
    final Adapter adapter = adapterView.getAdapter();
    if (adapter instanceof BaseAdapter) {
        ((BaseAdapter)adapter).notifyDataSetChanged();
    } else {
        throw new RuntimeException("Unexpected adapter");
    }

for example.

desseim
  • 7,968
  • 2
  • 24
  • 26
1

Make your adapter a field of the class instead of a local variable. Also, dont declare it using the ListAdapter interface, but a real class with the method that you need to use, so you dont need to cast, for instance

 BaseAdapter adapter = new SimpleAdapter(....

and also...please note that the data colection of your adapter, is in data, and you are deleting the item from dataHolder, that i dont know what is. please check that actually data is being changed when dataHolder changes, otherwise the list wont change.

I think that is the problem. when you call notifyDataSetChanged() it will check if data has changed. And probably it has not, and the adapter doesn't know how to get it again from dataHolder. Thats why it is not working. you should pass a variable that is changed inside the dataHolder, or create your own adatper that receives the dataholder as data, and call getAllData() to retrieve the update when notifyDataSetChanged() is called.

Other easier approach is that you create a public ArrayList <HashMap <String, String> > data in your dataHolder. That data is modified when you call deleteData or when you insert data to the dataHodler. And that dataHolder.data is what you pass to the adapter in the constructor:

new SimpleAdapter(MainActivity.this, dataHolder.data, R.layout.dataentry, new String[]{"unique_id","lastName"}, new int[]{R.id.unique_id,R.id.last_name});
Carlos Robles
  • 10,828
  • 3
  • 41
  • 60
  • I've tried what you suggest and add BaseAdapter adapter; as global variable. But it still doesn't refresh my ListView. It refreshes only when I exit the activity and open it again. – luwionline Jan 30 '14 at 10:44
  • what is dataHolder and how is it related to data? – Carlos Robles Jan 30 '14 at 10:45
  • "dataHolder" is a class where I create table in sqlite and insert my gathered data inside and the "data" is a method inside my dataHolder – luwionline Jan 30 '14 at 10:50
  • and what is the data variable that you pass to the adapter constructor? you get it from data holder calling data()? – Carlos Robles Jan 30 '14 at 10:52
  • i think that is the problem. when you call notifyDataSetChanged() it will check if data has changed. and probably it wont, and the adapter doesnt know how to get it again from dataHolder. thats why it is not working. you should pass a variable that is changed inside the dataHolder, or create your own adatper that receives the dataholder has data. – Carlos Robles Jan 30 '14 at 10:55
  • i guess it is what i say in the last comment. data array is not being changed. The best would be to create your own adapter, but that wont be the easier. The easier is that you create a `ArrayList > data` in your dataHolder. that data is modified when you call `deleteData` or when you insert data to the dataHodler. and that dataHolder.data is what you pass to the adapter in the constructor: `new SimpleAdapter(MainActivity.this, dataHolder.data, R.layout.dataentry, new String[]{"unique_id","lastName"}, new int[]{R.id.unique_id,R.id.last_name});` – Carlos Robles Jan 30 '14 at 11:03
  • check at my update, and please try it, im pretty sure it will work. – Carlos Robles Jan 30 '14 at 11:23
  • I'll try it later. I discovered another problem (the first item is the one that always being deleted) and I'm currently trying to solve it. – luwionline Jan 30 '14 at 15:52
  • ok, if you want, write another question and give me the link. Also dont forget to try to solve this problem so you can see if my answer works and upvote or accept or whatever so it is finally useful to other users, and also i get some value :) – Carlos Robles Jan 31 '14 at 06:10
  • I found the solution sir. data.remove(position) before the adapter.notifyDataSetChanged(); – luwionline Feb 22 '14 at 21:48
0

Solution found. Must remove first the item from the array list of the listview before notifying data set changed.

data.remove(position);
adapter.notifyDataSetChanged();
luwionline
  • 186
  • 2
  • 12
-1

just declare your ListAdapter as global variable

  • you are trying to access a local adapter inside an inner class that is the reason it is telling you to make it final.... so remove the ListAdapter from the local scope and declare it as global – nikhil_salunke Jan 30 '14 at 10:28