This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I'm building an app where I've to create multiple tables on a SQLite database.
The best example I can give is of one store that I'll have to manage, so I'm creating one table for each category (wines, beers, milk, etc...) of products where I have to manage the brands that I'm selling but, if I quit from selling one of this categories I would like to be able to drop this category table.
But I tried many examples from the web and nothing works. I'm always getting the same error.
Because I've many items on my tables I built a custom list view and a custom adapter and both are working perfectly, I can delete or add new items without problems, build new tables, but the same approach doesn't work to drop my built tables.
I intentionally let my database opened until my activity is destroyed so I don't have to open it trough my adapter.
Maybe someone can help me how to drop a table with the name passed from a String, using one button or in this case, would be really helpful using my adapter button, because my idea is to add buttons on my list view.
Just to make clear, I can drop the tables if I create one editText to type my tables names and use a button to run this code:
dataBase.execSQL("DROP TABLE IF EXISTS '" + tableName + "'");
or if I run this code during the execution of the method onCreate and I give a name from a table that really exists.
dataBase.execSQL("DROP TABLE IF EXISTS 'test 1'");
So my question is not how to handle NullPointerException but how to manipulate my SQLite database from my custom adapter.
Thank you!
this is my adapter code:
public class MyCustomAdapter extends BaseAdapter implements ListAdapter {
private ArrayList<String> list = new ArrayList<String>();
private Context context;
private SQLiteDatabase dataBase;
private String tableName;
public MyCustomAdapter(ArrayList<String> list, Context context) {
this.list = list;
this.context = context;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int pos) {
return list.get(pos);
}
#Override
public long getItemId(int pos) {
//return list.get(pos).getId();
//just return 0 if your list items do not have an Id variable.
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_item_clickable, null);
}
//Handle TextView and display string from your list
TextView listItemText = (TextView)view.findViewById(R.id.list_item_textview);
listItemText.setText(list.get(position));
//Handle buttons and add onClickListeners
Button deleteBtn = (Button)view.findViewById(R.id.delete_btn);
deleteBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
//criar alertDialog
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("Delete!");
dialog.setMessage("Do you wish to delete this ToDo list?");
dialog.setCancelable(false);
dialog.setIcon(android.R.drawable.ic_delete);
dialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(context, "No!", Toast.LENGTH_SHORT).show();
}
});
dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
final String tableName= list.get( position ).toString();
try {
dataBase.execSQL("DROP TABLE IF EXISTS '" + tableName + "'");
//dataBase.execSQL("DROP TABLE IF EXISTS 'test 1'");
list.remove(position); //or some other task
Toast.makeText(context, "Tabela " + tableName + " removida com sucesso!", Toast.LENGTH_SHORT).show();
notifyDataSetChanged();
} catch (Exception e) {
e.printStackTrace();
}
}
});
dialog.create();
dialog.show();
}
});
listItemText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Toast.makeText(context, "Item position is: " + list.get(position), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(context, MainActivity.class);
String tabelaNome = list.get( position ).toString();
intent.putExtra("tableName", tableName);
context.startActivity(intent);
}
});
return view;
}
Error message
Note the difference between your two SQL statements:
dataBase.execSQL("DROP TABLE IF EXISTS '" + tableName + "'");
dataBase.execSQL("DROP TABLE IF EXISTS teste 1");
The one you say works does not have quotes around the table name.
Related
On deleting the item from the Listview the item gets deleted at that time, but on coming back to the activity the item reappears.
This is my Main2Activity code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
position = intent.getIntExtra("position", 0);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listItem);
listView.setAdapter(adapter);
viewData1();
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int pos, long id) {
final int itemToDelete = pos;
new AlertDialog.Builder(Main2Activity.this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Are you sure?")
.setMessage("Do you want to delete this location?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
listItem.remove(itemToDelete);
databaseHelper1.deleteLocation(itemToDelete, position);
adapter.notifyDataSetChanged();
}
}
)
.setNegativeButton("No", null)
.show();
return true;
}
});
}
private void viewData1() {
Cursor cursor = databaseHelper1.viewData1(position);
if (cursor.getCount() == 0) {
Toast.makeText(this, "No data to show", Toast.LENGTH_SHORT).show();
} else {
while (cursor.moveToNext()) {
Log.i("message", "Data got");
listItem.add(cursor.getString(1));
}
adapter.notifyDataSetChanged();
}
}
DatabaseHelper:
public void deleteLocation(int itemToDelete,int position)
{
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
String itemDelete = Integer.toString(itemToDelete);
Log.i("itemdel",itemDelete);
if(position ==0)
{
String Id = (ID1);
Log.i("Id",Id);
String query = " Delete from "+DB_TABLE1 + " where "+ Id + " = " + itemDelete;
sqLiteDatabase.execSQL(query);
sqLiteDatabase.delete(DB_TABLE1,ID1 + " = "+ itemDelete, null);
sqLiteDatabase.compileStatement(query);
Log.i("del"," executed")
}
}
public Cursor viewData1(int position)
{
SQLiteDatabase sqLiteDatabase = this.getReadableDatabase();
Cursor cursor = null;
if (position ==0)
{
String query = "Select * from " + DB_TABLE1;
cursor = sqLiteDatabase.rawQuery(query, null);
}
return cursor;
}
What happens is:
Before Deleting:
After Deleting garden:
On restarting activity:
How do I commit the delete to the database? Thanks.
Your issue is that you are assuming that position (3rd parameter passed to the onItemLongClick method) directly relates to the id of the row.
You cannot rely on a correlation between position and id.
The first position in the list will be at position 0. The lowest ID allocated (unless forced) will be 1. However adding 1 is not a solution as even though it may initially work. As soon as you delete anything other than the last item in the list then an id is omitted from the list of id's and you may not delete a row or you may delete a different row.
The most sensible/easiest fix is to utilise a CursorAdapter i.e. SimpleCursorAdapter in which case the 4th parameter to onItemClick and onItemLongClick (long l) will be the actual id. However, to utilise a CursorAdapter you MUST have the id column named as _id (hence why there is the constant BaseColumns._ID).
You could always rename the column when extracting it using AS e.g. SELECT rowid AS _id, * FROM the_table; (which will select all existing columns AND the id column).
Here's a link to a more comprehensive answer with options for other adapter Deleting item from ListView and Database with OnItemClickListener
I used custom adapter for viewing listview. I tried to define my variables in adapter class but it didnt work. I find a temporary solution using invisible textview for this but i need to solve this problem. How can I overcome this?
Edit 1>
I have a column named date and this column contains datas like 20180723182036 and i grab this data to a list. I want to place this to listview as a variable and i will use this variable later.
My temporary solution is:
I have a code like that in database:
public ArrayList<SimpleNoteItem> getAllData() {
openDatabase();
ArrayList<SimpleNoteItem> newList = new ArrayList<>();
String[] columns = {KEY_ROWTITLE, KEY_ROWCONTENT, KEY_ROWDATE, KEY_ROWSTRDATE};
Cursor cs = db.query(DB_TABLE_NORMAL, columns, null, null, null, null, null);
while(cs.moveToNext()){
SimpleNoteItem allData = new SimpleNoteItem(cs.getString(0), cs.getString(1), cs.getLong(2), cs.getString(3));
newList.add(allData);
}
Collections.reverse(newList);
Log.d(LOGDB, "GETALLDATA STRUCTURE WORKS WELL!");
return newList;
}
Listview longclick constructor is this:
simpleNotesDisplay.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, final long id) {
Log.d(TAG, "LONG CLICKED " + position + " ITEM!");
//THIS AREA WILL BE EDITED FOR MORE ANDROID VERSION SUPPORT
AlertDialog.Builder builder;
final TextView getInvisibleDate = (TextView) view.findViewById(R.id.tv_date_invisible);
builder = new AlertDialog.Builder(NotesActivity.this, android.R.style.Theme_Material_Dialog_Alert);
builder.setTitle("Delete?")
.setMessage("Do you want to send this note to hell?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
db.deleteSimpleNote(getInvisibleDate.getText().toString());
Log.d(TAG, "DELETING SUCCESSFUL ON ID = " + id + "!!!");
NotesActivity.this.recreate();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//empty
}
})
.show();
return true;
}
});
}
And at least my invisible date:
<TextView
android:id="#+id/tv_date_invisible"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="TextView"
android:visibility="invisible"
tools:layout_editor_absoluteX="351dp"
tools:layout_editor_absoluteY="65dp" />
i hope it can help!
you should better to explain more about what you want but:
1)if you want to show some data in listview you most have a list of objects that each one has its data.
2)if you want to show different data in each row of listview then you most fill different data in each object of your list
3) if you want to show different view of each listviews row you most at first define different xml layouts and in your adapter where you define infelater you can use if else statment to decide which layout shows to witch row. below links will help you
Android ListView with different layouts for each row
https://www.javacodegeeks.com/2014/08/android-listview-with-multiple-row-layout.html
I found a different solution for that>>
I grab all data from database with this code:
public ArrayList<SimpleNoteItem> getAllData() {
openDatabase();
ArrayList<SimpleNoteItem> newList = new ArrayList<>();
String[] columns = {KEY_ROWTITLE, KEY_ROWCONTENT, KEY_ROWDATE, KEY_ROWSTRDATE};
Cursor cs = db.query(DB_TABLE_NORMAL, columns, null, null, null, null, null);
while(cs.moveToNext()){
SimpleNoteItem allData = new SimpleNoteItem(cs.getString(0), cs.getString(1), cs.getLong(2), cs.getString(3));
newList.add(allData);
}
Collections.reverse(newList);
Log.d(LOGDB, "GETALLDATA STRUCTURE WORKS WELL!");
return newList;
}
And in another activity i grab this list with this and then initialized it:
private ArrayList<SimpleNoteItem> getList = new ArrayList<>();
getList = db.getAllData();
initialize should be in onCreate method.
And then i used that data:
simpleNotesDisplay.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, final long id) {
Log.d(TAG, "LONG CLICKED " + position + " ITEM!");
//THIS AREA WILL BE EDITED FOR MORE ANDROID VERSION SUPPORT
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(NotesActivity.this, android.R.style.Theme_Material_Dialog_Alert);
builder.setTitle("Delete?")
.setMessage("Do you want to send this note to hell?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
db.deleteSimpleNote(String.valueOf(getList.get(position).getSimpleNoteDate()));
Log.d(TAG, "DELETING SUCCESSFUL ON ID = " + id + "!!!");
NotesActivity.this.recreate();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//empty
}
})
.show();
return true;
}
});
I have created a database which is displayed in a ListView using an ArrayAdapter. I want a selected ListView item to be deleted when a ContextMenu pops up with a delete option as depicted below:
I have a class for handling all the database functions like delete. When I use a normal onCLicklistener with a button, the delete function is performed correctly, i.e it deletes the correct database entry and reaches the if (cursor.moveToFirst()) line. When I make use of the delete menu item, it does not reach the if (cursor.moveToFirst()) line in the attached delete handler function and therefore does not delete the entry (attached after the ListView code snippet below is the delete handler).
Any help/guidance/examples will be greatly appreciated.
My ListView is populated as follows:
public class Listview extends AppCompatActivity
{
private ListView users;
FloatingActionButton fab;
MyDBHandler dbHandler;
ArrayAdapter<String> arrayAdapter;
String lists;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.activity_listview);
// Create back button in action bar
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
users = (ListView) findViewById(R.id.clientlst);
// Floating Action bar for adding new data entries
fab = (FloatingActionButton) findViewById(R.id.fab1);
MyDBHandler dbHandler = new MyDBHandler(getApplicationContext());
lists = dbHandler.loadHandler();
//Create a list of the saved database String array items and split into
Strings
ArrayList<String> list = new ArrayList<>
(Arrays.asList(lists.split("\n")));
// Create the List view adapter
arrayAdapter = new ArrayAdapter<String>(Listview.this,
android.R.layout.simple_list_item_1, android.R.id.text1, list)
{
#Override // Edit the Text colour of the Listview items
public View getView(int position, View convertView, ViewGroup parent)
{
String Items = arrayAdapter.getItem(position);
String[] separated = Items.split(":");
String Name123 = separated[1]; // This will contain "Name"
TextView textView = (TextView) super.getView(position,
convertView, parent);
textView.setTextColor(Color.BLUE);
textView.setText(Name123);
return textView;
}
};
users.setAdapter(arrayAdapter);
registerForContextMenu(users);
// Create an action to be performed by each click of an item in the
users.setOnItemClickListener
(
new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View
view, int position, long id) {
String Items = arrayAdapter.getItem(position);
String[] separated = Items.split(":");
String ip = separated[5]; // This will contain "PORT address"
String port = separated[3]; // This will contain "IP number"
Toast.makeText(Listview.this, port + ip,
Toast.LENGTH_LONG).show();
} // onItemClick
} // OnItemClickListener View
); // OnItemClickListener
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
Toast.makeText(Listview.this, "Fab
Clicked", Toast.LENGTH_LONG).show();
}
}
);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle("Choose an option");
MenuInflater inflator = getMenuInflater();
inflator.inflate(R.menu.example_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item)
{
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId())
{
case R.id.option_1:
arrayAdapter.getItem(info.position);
MyDBHandler dbHandler = new MyDBHandler(getApplicationContext());
String Items= arrayAdapter.getItem(info.position);
String[] separated = Items.split(":");
String ip = separated[3]; // This will
contain "IP addr"
String names = separated[1]; // This will
contain "Name"
Log.d("LATE",names + ip);
dbHandler.deleteHandler(names,ip);
arrayAdapter.notifyDataSetChanged(); // Refresh the
listview
Toast.makeText(this, "Deleted", Toast.LENGTH_SHORT).show();
Intent listviews1 = new Intent(Listview.this, Listview.class);
startActivity(listviews1);
return true;
case R.id.option_2:
Intent listviews2 = new Intent(Listview.this, Listview.class);
startActivity(listviews2);
Toast.makeText(this, "Updated", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onContextItemSelected(item);
}
}
}
The delete handler function of the database is as follows:
public void deleteHandler(String username, String IP)
{
//boolean result = false;
String query = "Select*FROM " + TABLE_USER + " WHERE " + COLUMN_NAME + "
= '" + String.valueOf(username) + "'" + " and " + COLUMN_ID + " = '" +
String.valueOf(IP) + "'";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
Log.d ("MEH", String.valueOf(cursor));
User user = new User();
if (cursor.moveToFirst())
{
user.setUserName(cursor.getString(2));
user.setID(cursor.getString(3));
db.delete(TABLE_USER, COLUMN_NAME + "=? and " + COLUMN_ID + "=?",
new String[]
{
String.valueOf(user.getUserName()),
String.valueOf(user.getID())
});
cursor.close();
//result = true;
}
db.close();
//return result;
}
You aren't calling any method to delete the item from the database from your users.setOnItemClickListener
As you added in your comment, all you are doing is trying to delete the item from your ActionBar's onItemClicked method.
Do the same inside your OnItemClickListener
Update2: Change in requirement
users.setLongClickable(true);
users.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
//Do your tasks here
AlertDialog.Builder alert = new AlertDialog.Builder(
YourActivity.this);
alert.setTitle("Alert!!");
alert.setMessage("Choose an option");
alert.setPositiveButton("Edit", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//do your work here
dialog.dismiss();
}
});
alert.setNegativeButton("Delete", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//perform your delete callback here
dialog.dismiss();
}
});
alert.show();
return true;
}
});
Update1: Explanation to Amiya's answer,
The reason why
cursor.moveToFirst() isn't a good option is because this statement
is unnecessary. The compiler knows exact spot to hit when it will
enter inside your DB. One usually perform cursor.moveToFirst()
when you need to iterate through all or some data elements from your
database.
"Make sure, COLUMN_ID is PRIMARY Key." Reason behind this is to avoid duplicity in case you ever add a functionality of adding items on the run time.
REMOVE this if (cursor.moveToFirst()) .
Make sure, COLUMN_ID is PRIMARY Key.
Check deleteHandler() method is invoking or not.
You should try with
public void deleteHandler(String username, String IP)
{
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_USER,
COLUMN_NAME + " = ? AND " + COLUMN_ID + " = ?",
new String[] {username, IP});
db.close();
}
I want to delete a row in my Database via a ListView. I already managed to display the data in a listview. I am working with a OnItemLongClickListener which then opens up a Dialog to delete the clicked item. I can't get the actual delete method to work.
The OnCLickListener method:
public boolean onItemLongClick(AdapterView<?> adapterView, View view, final int position, long id) {
build = new AlertDialog.Builder(ZeigeFaecherListe.this);
build.setTitle("Fach löschen?" + faecherListe.get(position));
build.setMessage("Willst du das Fach wirklich löschen?");
build.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
build.setPositiveButton("Löschen", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
myDb.loescheFach(position);
Toast.makeText(getApplicationContext(), faecherListe.get(position) + " gelöscht.", Toast.LENGTH_LONG).show();
myDb.zeigeFaecher();
dialogInterface.cancel();
}
});
AlertDialog alert = build.create();
alert.show();
return true;
}
});
The actual delete method:
public int loescheFach(int position){
SQLiteDatabase db = this.getWritableDatabase();
return db.delete("Fach_table","FACHID=?", new String[]{String.valueOf(position)});
}
You are confusing your list position with id, they might not match.
Change your myDb.loescheFach(position); to myDb.loescheFach(id);
You're passing the position of ArrayList to SQLite to delete statement. You should pass FACHID (in your case) as an argument to delete statement.
As your posted code is incomplete I assume it as below.
....
....
build.setPositiveButton("Löschen", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
// myDb.loescheFach(position);
// first get an id from ArrayList using position faecherListe.get(position)
// then pass that id to your method
myDb.loescheFach(id);
Toast.makeText(getApplicationContext(), faecherListe.get(position) + " gelöscht.", Toast.LENGTH_LONG).show();
myDb.zeigeFaecher();
dialogInterface.cancel();
}
});
....
....
First position will not equate to the rowid/id of the row in the table. Assuming that you have a id column defined as your_id_column INTEGER PRIMARY KEY (or with the AUTOINCREMENT keyword, that makes no real difference) and that you don't specify a value when inserting a row then the first id will likely be 1, then 2 then 3 ... etc.
However, position (3rd parameter passed to onItemClick/onItemLongClick) for the first item in the List will be 0, then 1 then 2 etc. So you will never actually delete correct row (clicking the first item will delete nothing, clicking the second item will delete the first) and when rows are deleted it gets even more out of sync.
The 4th parameter (long id) passed will be the rowid/id IF AND ONLY IF a CursorAdapter is used (i.e. a Cursor is the source data for the ListView). In which case the cursor MUST have a column named _id. However, it looks as though faecherListe is the source and as you use the get method that it is an ArrayList/List. As such the id passed will be the same value position except it is a long.
Now if faecherListe were an ArrayList<object_that_reflects_the_columns_of_the_table_including_id> then assuming a getter of getId you could use long retrieved_id = faecherListe.get(position).getId(). However, the comments :-
I guess you have ArrayList of String, that's why are getting String
value from ArrayList – Shashanth 10 hours ago
Ye
You simply have ArrayList and thus no means of ascertaining the id unless whatever data is held by the String is guaranteed to be unique.
Example
This is an example using object_that_reflects_the_columns_of_the_table_including_id in this case a Feacher class that just has a name and an id
Feacher.java
This is an entirely new class that allows you to have an ArrayList with all the relevant data/fields/columns (especially the id column).
i.e. you can an have ArrayList
public class Feacher {
private String name;
private long id;
public Feacher(String feacher_name) {
this(feacher_name,-1);
}
public Feacher(String feacher_name, long feacher_id) {
this.name = feacher_name;
this.id = feacher_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String toString() {
return name + " ID(" + String.valueOf(id) + ")";
}
}
DBHelper
This is the database helper (sub class of SQLiteOpenHelper) :-
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "feacher.db";
public static final int DBVERSION = 1;
public static final String TB_FEACHER = "feacher";
public static final String COL_FEACHER_ID = BaseColumns._ID;
public static final String COL_FEACHER_NAME = "feacher_name";
SQLiteDatabase mDB;
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
String crtsql = "CREATE TABLE IF NOT EXISTS " + TB_FEACHER +
"(" +
COL_FEACHER_ID + " INTEGER PRIMARY KEY," +
COL_FEACHER_NAME + " TEXT" +
")";
db.execSQL(crtsql);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public long addFeacher(String feacher_name) {
ContentValues cv = new ContentValues();
cv.put(COL_FEACHER_NAME,feacher_name);
return mDB.insert(TB_FEACHER,null,cv);
}
public ArrayList<Feacher> getAllAsFeacherArrayList() {
ArrayList<Feacher> rv = new ArrayList<>();
Cursor csr = mDB.query(
TB_FEACHER,
null,
null,
null,
null,
null,
null
);
while (csr.moveToNext()) {
rv.add(new Feacher(
csr.getString(csr.getColumnIndex(COL_FEACHER_NAME)),
csr.getLong(csr.getColumnIndex(COL_FEACHER_ID))
)
);
}
return rv;
}
public int deleteFeacher(long id) {
return mDB.delete(
TB_FEACHER,
COL_FEACHER_ID + "=?"
,new String[]{String.valueOf(id)}
);
}
}
the deleteFeacher method to delete a row according to it's id,
the addFeacher method allowing some test data to be added.
the getAllAsFeacherArrayList returns all data as an ArrayList (note uses the constructor that sets the id)
MainActivity.java
The activity that has the ListView.
public class MainActivity extends AppCompatActivity {
ListView mListView;
ArrayAdapter<Feacher> mAdapter;
DBHelper mDBHlpr;
ArrayList<Feacher> mFeacherList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = this.findViewById(R.id.listview);
mDBHlpr = new DBHelper(this);
addDataForTesting();
displayAdapter();
}
private void displayAdapter() {
if (mFeacherList == null) {
mFeacherList = mDBHlpr.getAllAsFeacherArrayList();
} else {
mFeacherList.clear();
for (Feacher f: mDBHlpr.getAllAsFeacherArrayList()) {
mFeacherList.add(f);
mAdapter.notifyDataSetChanged();
}
}
if (mAdapter == null) {
mAdapter = new ArrayAdapter<Feacher>(this,android.R.layout.simple_list_item_1,mFeacherList);
mListView.setAdapter(mAdapter);
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
mDBHlpr.deleteFeacher(mAdapter.getItem(i).getId());
displayAdapter();
return true;
}
});
}
}
private void addDataForTesting() {
mDBHlpr.addFeacher("Feacher 001");
mDBHlpr.addFeacher("Feacher 002");
mDBHlpr.addFeacher("Feacher 003");
}
}
Note for simplicity and also to avoid inadvertent deletion onItemLongClick has been used. The all important bit being mDBHlpr.deleteFeacher(mAdapter.getItem(i).getId()); which gets the id from the item (object, the Feacher) that was clicked according to the position.
activity_main.xml
A very basic layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<ListView
android:id="#+id/listview"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFAAAAFF"
>
</ListView>
</LinearLayout>
Result
here's a screen shot after 3rd run so 9 rows have been added and 2 rows have been deleted (note id's 2 and 5 are missing). The list will refresh after a deletion so the row disappears almost immediately the long-click is completed.
I have a listview that contains some data which I got from the web. Now I can make changes in the list item and once I make changes to the item, I am storing the updated value in the db. When i login in next time to the app, I am downloading the content from net and showing it in the listview with the changes that I have done last time. So my approach here is, I am querying the db for each item in the getview method of the list adapter to check for changes. Is it a good practice to do a db query for each item's getview method of the adapter? If not could you please suggest me some alternative. Thanks.
Never, really, never do that.
If you put your data download code in the getView method of the adapter it will make a network call for each row of the list.
Even worst, it will call it anytime that row appears on the screen, not only one time for row.
You should get all your data first, then use the adapter only to draw it.
You can at anytime call the db to check for changes and, if needed, notify the adapter to redraw the list to show the changes.
Hope this helps.
In Android development, any time you want to show a vertical list of items you will want to use a ListView which is populated using an Adapter to a data source. When we want the data for the list to be sourced directly from a SQLite database query we can use a CursorAdapter.
The CursorAdapter fits in between a Cursor (data source from SQLite query) and the ListView (visual representation) and configures two aspects:
Which layout template to inflate for an item
Which fields of the cursor to bind to views in the template
Creating the View Template
When we want to display a series of items into a list using a custom representation of the items, we need to use our own custom XML layout template for each item. We can simply create an XML layout template in res/layout/item_todo.xml representing a particular cursor row:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/tvBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Study cursors"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/tvPriority"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="3"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
Defining the Adapter
public class ViewAdapter extends BaseAdapter {
LayoutInflater mInflater;
public ViewAdapter() {
mInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return favoriteList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem,null);
}
final TextView nameText = (TextView) convertView.findViewById(R.id.nameText);
nameText.setText("Name : "+favoriteList.get(position).getName());
final TextView ageText = (TextView) convertView.findViewById(R.id.ageText);
ageText.setText("Age : "+favoriteList.get(position).getAge());
final Button edit = (Button) convertView.findViewById(R.id.edit);
edit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new Dialog(context);
dialog.setContentView(R.layout.row);
dialog.setTitle("Add Data to Database");
final EditText name = (EditText) dialog.findViewById(R.id.name);
final EditText age = (EditText) dialog.findViewById(R.id.age);
Button Add = (Button) dialog.findViewById(R.id.Add);
Add.setText("Add");
Add.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(name.getText().toString() != null && name.getText().toString().length() >0 ){
if(age.getText().toString() != null && age.getText().toString().length() >0 ){
db.updateRow(favoriteList.get(position).getId(), name.getText().toString(), age.getText().toString());
favoriteList = db.getFavList();
listView.setAdapter(new ViewAdapter());
dialog.dismiss();
}else{
Toast.makeText(getApplicationContext(), "Please Enter the Age", Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getApplicationContext(), "Please Enter the Name", Toast.LENGTH_LONG).show();
}
}
});
dialog.show();
}
});
final Button delete = (Button) convertView.findViewById(R.id.delete);
delete.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
db.removeFav(favoriteList.get(position).getId());
notifyDataSetChanged();
favoriteList = db.getFavList();
listView.setAdapter(new ViewAdapter());
}
});
return convertView;
}
}
Create database
DatabaseHandler.java
public class DatabaseHandler extends SQLiteOpenHelper {
//Database Version
private static final int DATABASE_VERSION = 1;
//Database Name
private static final String DATABASE_NAME = "Test";
//Table Name
private static final String TABLE_TEST = "TestTable";
//Column Name
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_AGE = "age";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//Create Table
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_TEST + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
+ KEY_AGE + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TEST);
onCreate(db);
}
//Insert Value
public void adddata(Context context,String movieId,String songId) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, movieId);
values.put(KEY_AGE, songId);
db.insert(TABLE_TEST, null, values);
db.close();
}
//Get Row Count
public int getCount() {
String countQuery = "SELECT * FROM " + TABLE_TEST;
int count = 0;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
if(cursor != null && !cursor.isClosed()){
count = cursor.getCount();
cursor.close();
}
return count;
}
//Delete Query
public void removeFav(int id) {
String countQuery = "DELETE FROM " + TABLE_TEST + " where " + KEY_ID + "= " + id ;
SQLiteDatabase db = this.getReadableDatabase();
db.execSQL(countQuery);
}
//Get FavList
public List<FavoriteList> getFavList(){
String selectQuery = "SELECT * FROM " + TABLE_TEST;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
List<FavoriteList> FavList = new ArrayList<FavoriteList>();
if (cursor.moveToFirst()) {
do {
FavoriteList list = new FavoriteList();
list.setId(Integer.parseInt(cursor.getString(0)));
list.setName(cursor.getString(1));
list.setAge(cursor.getString(2));
FavList.add(list);
} while (cursor.moveToNext());
}
return FavList;
}
}
Enojoys.... :)
It is better to use cursor adapter to bind the list view.You can use Loader to get the list updated even if there is a change in the data base.
onLoadFinished (Loader loader, D data) of the Loader call back would be monitor for changes to the data, and report them to you through new calls. You should not monitor the data yourself.