0

I have a listview on which i am showing data from my database and now i want to delete row on the basis of button clicked which is associated with each row.

i am having exception in CustomAdapter class whenever i press Done button. CursorAdapter code is this:

public class CustomAdapter extends CursorAdapter {
  TextView task,daate;
  Button del;
  public static int id;
  Context ct;
  public CustomAdapter(Context context, Cursor cursor) {
    super(context, cursor, 0);
}

// The newView method is used to inflate a new view and return it,
// you don't bind any data to the view at this point.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    ct=context;
    return LayoutInflater.from(context).inflate(R.layout.adapter, parent, false);

}

// The bindView method is used to bind all data to a given view
// such as setting the text on a TextView.
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final DatabaseHelper help=new DatabaseHelper(ct);
    del = (Button) convertView.findViewById(R.id.deleteBtn);
    del.setOnClickListener( new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                  help.deleteRecordWithId(position);
                                }
                            }
    );
    return super.getView(position, convertView, parent);
}


@Override
public void bindView(View view, Context context, final Cursor cursor) {
    // Find fields to populate in inflated template
        task = (TextView) view.findViewById(R.id.dynamicTask);
        daate = (TextView) view.findViewById(R.id.dynamicDate);
        id=cursor.getInt(cursor.getColumnIndex("_id"));
    String Task=cursor.getString(cursor.getColumnIndex("task"));
    String Daate=cursor.getString(cursor.getColumnIndex("ddate"));
    task.setText(Task);
    daate.setText(Daate);
}

}

and my database function deleteRecordWithId() is:

 public boolean deleteRecordWithId(int id) {
    SQLiteDatabase db=this.getWritableDatabase();
    long rows=db.delete(TABLE_NAME,"_id=?",new String[] {String.valueOf(id)});
    if(rows>0) {
        return  true;
    }
    else {
        return false;
    }
}

and i am getting this exception:

  java.lang.NullPointerException: Attempt to invoke virtual method 
  'android.view.View android.view.View.findViewById(int)' on a null object 
  reference

What is wrong in this code. please help me to rectify it.

Samir Bhatt
  • 3,041
  • 2
  • 25
  • 39
Suraj
  • 41
  • 7
  • 1
    Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Dima Kozhevin Nov 03 '17 at 06:58
  • The View on which you are calling `findViewById` is null. Check whether you are initializing the view. Also, use `RecyclerView` and not `ListView`since it is perfomance efficient – Saran Sankaran Nov 03 '17 at 07:01
  • why it is showing nullpointer exception? i have defined it using its id – Suraj Nov 03 '17 at 07:01

4 Answers4

1

Replace this:

help.deleteRecordWithId(position);

with:

CustomAdapter.this.remove(CustomAdapter.this.getItem(position));
CustomAdapter.this.notifyDataSetChanged();

It will delete data from your adapter and notifydatasetchanged will update your listview accordingly.

Muhammad Saad Rafique
  • 3,158
  • 1
  • 13
  • 21
  • It will surely work if other than that remaining code is working. Do let me know if it works and for further assistance too if required. Don't forget to mark this as answer if it works for you. Happy coding bro :) – Muhammad Saad Rafique Nov 03 '17 at 07:49
  • remove is method to delete from arrayAdapter you are using cursorAdapter for that deleteRecordwithId will do the job, give it a try – Muhammad Saad Rafique Nov 03 '17 at 09:24
  • Try CustomAdapter.this.deleteRecordWithId(position); let me know if it works so I may update answer . Because it will help others in future. – Muhammad Saad Rafique Nov 03 '17 at 09:26
  • Ok buddy then google "Cursor adapter method to remove entry from it at specific position" . See documentation it will take you to the specific method to remove it from adapter. Hope you will solve it soon. Happy coding bro :) – Muhammad Saad Rafique Nov 03 '17 at 10:42
0

set setOnItemClickListener to your listview...

yourListView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            yourListView.remove(position);
            database.removeItem(id);//create removemethod in database class

        }
    });

Define removeItem method

public void remove(long id){
        String str =String.valueOf(id);
        database.execSQL("DELETE FROM <TABLE_NAME> WHERE _id = '" + str + "'");
    }
Flutterian
  • 1,761
  • 1
  • 21
  • 47
  • yes i tells that check from where the values are coming to that on which you are getting nullpointer exception – Suraj Nov 03 '17 at 07:26
  • Thanks for the above code but, it doesn't have any button. I have to try using a button – Suraj Nov 03 '17 at 07:28
  • You might be looking for [this](https://stackoverflow.com/questions/7831395/android-how-to-delete-a-row-from-a-listview-with-a-delete-button-in-the-row) solution. Please check once. – Flutterian Nov 03 '17 at 07:34
  • thanks for this, but i already used this before and the function getLayoutInflator() is not available, when i use this LayoutInflater inflater = getLayoutInflater(); it shows "can't resolve getLayoutInflator()" – Suraj Nov 03 '17 at 07:41
  • Try this... `LayoutInflater inflater= getActivity().getLayoutInflater();` or `LayoutInflater inflater= youContext.getLayoutInflater();` – Flutterian Nov 03 '17 at 07:53
0

First Method: You describe like that

public class CustomAdapter extends CursorAdapter {

TextView task,daate;
Button del;
public static int id;
Context ct;
public CustomAdapter(Context context, Cursor cursor) {
    super(context, cursor, 0);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    ct=context;
    return LayoutInflater.from(context).inflate(R.layout.adapter, parent, false);

}

@Override
public void bindView(View view, Context context, final Cursor cursor) {
    // Find fields to populate in inflated template
    task = (TextView) view.findViewById(R.id.dynamicTask);
    daate = (TextView) view.findViewById(R.id.dynamicDate);
    id=cursor.getInt(cursor.getColumnIndex("_id"));
    String Task=cursor.getString(cursor.getColumnIndex("task"));
    String Daate=cursor.getString(cursor.getColumnIndex("ddate"));
    task.setText(Task);
    daate.setText(Daate);
    final DatabaseHelper help=new DatabaseHelper(ct);
    del = (Button) convertView.findViewById(R.id.deleteBtn);
}}

MainActivity:

public class MainActivity{
private CustomAdapter cursorAdapter;
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    cursorAdapter = new CustomAdapter(this, null);
}
public void deleteRecordWithId(View view) {
    View parentRow = (View) view.getParent().getParent();
    ListView listView = (ListView) view.getParent().getParent().getParent();
    int position = listView.getPositionForView(parentRow);
    long id = cursorAdapter.getItemId(position);

    SQLiteDatabase db=this.getWritableDatabase();
long rows=db.delete(TABLE_NAME,"_id=?",new String[] {String.valueOf(id)});
if(rows>0) {
    return  true;
}
else {
    return false;
}
}
}

and xml like that:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/task_outer_container"
                android:layout_width="match_parent"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:gravity="center_vertical"
                android:background="@drawable/background_transparent"
                android:layout_height="wrap_content"
                android:clipToPadding="false"
                android:clipChildren="false"
    >
    <ImageButton
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:id="@+id/delete_button"
        android:onClick="deleteRecordWithId"
        app:srcCompat="@drawable/remove_icon"
        android:background="@drawable/background_transparent"
        android:layout_gravity="center_vertical"
        android:adjustViewBounds="false"
        android:paddingStart="7dp"
        android:paddingEnd="7dp"
        android:layout_marginEnd="-5dp"/>

</RelativeLayout>

Second Method: You should not use getView in the Cursoradapter. You need to do all the operations in bindview. So uou can not reach id with getview.

For example: https://github.com/rodoggx/w4d1_Simple_CursorAdapter/blob/master/app/src/main/java/com/example/sqlitecursoradapter/CustomAdapter.java

Umut ADALI
  • 1,146
  • 1
  • 14
  • 31
  • ok. but how i gonna use position of that very button that will be clicked without using getView() – Suraj Nov 03 '17 at 07:33
  • i think this solve your problem. https://stackoverflow.com/questions/27666203/get-a-position-in-bindview-using-cursoradapter or https://stackoverflow.com/questions/28207830/custom-cursor-adapter-get-position – Umut ADALI Nov 03 '17 at 07:35
  • this code is working but not proper. Thanks for sharing this it helped me a lot in understanding the big picture but the thing is when i use position inside onclick it tells me to declare it final. if i will do it final, the value of it will never change – Suraj Nov 03 '17 at 08:37
  • I edited my answers and add code you do like this ;) – Umut ADALI Nov 03 '17 at 14:55
0

ListView doesn't give a straightforward way to implement actions to views inside an item. Use RecyclerView instead, it's more customizable and good for performance than the list view.

Create Lists and Cards - Android Developer

UdeshUK
  • 972
  • 1
  • 11
  • 19