I am using a local sqlite db that is saving everything properly. When I open up a group in the expandableListView, all the checkboxes that have been stored in the db the check box is checked. When I edit an entry(I used an AlertDialog), close the group and then reopen the group. The checkbox is no longer checked. I checked the db and the edit was saved. If I go to another page and come back, once I click on the group, the child item I edited is once again checked. I used breakpoints in eclipse and it seems to find the data in the db, but not mark the box as checked. Any ideas?
This is the image of when I first click on the group(Engine)
Now I am using an AlertDialog to update the entry
Now I close the group
When I reopen the box by Battery is no longer checked.
Here is the code for when I open a group
public void onGroupExpand(int groupPosition)
{
db= new InspectionRecordsTableDBAdapter(getBaseContext());
db.open();
int inspectionId = com.signalsetapp.inspectionchecklist.report
.returnStringID();
String [] child=kids[groupPosition];
ArrayList<Color> secList = new ArrayList<Color>();
for(int i=0; i<child.length;i++)
{
try {
if (db.childFound(inspectionId, child[i]))
secList.add(new Color(child[i], true));
else
secList.add(new Color(child[i], false));
} catch (Exception e) {
secList.add(new Color(child[i], false));
e.printStackTrace();
}
}
}
and here is the update code the save into the db. This does save properly into the db
db.editRecords(
primaryId,
com.signalsetapp.inspectionchecklist.report
.returnStringID(),
parent[groupPosition],
kids[groupPosition][childPosition],
input.getText().toString(), status);
onExpand=true;
You should requery() your group cursor after you save to the database and it should regenerate the list views ( or the asynchronous equivalent since requery has been deprecated).
Related
I have a delete Row function as according:
public boolean removeData(int position) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, COL_ID+"="+position, null);
return true;
}
This function deletes a row according to its unique ID.
How can I change this so that after deleting a row, all rows below that one will be moved up to fill the empty space in the database?
That's against the design principle of a relational database. The rows are not ordered in a predictable way. So after delete you can only be sure that the deleted record appears to be away, but you have no control on the physical locations of any record, including which record(s), if any, now cover the space of the deleted one.
Querying data is another topic. You can specify a sort order, available as a parameter with the query methods. When querying your table, the results will appear exactly as you want it: If previously your results were Adam, Eve, Jack, Michael, then after deleting Jack, the result will be Adam, Eve, Michael.
The interplay between the displayed list, the domain objects behind that list, and the database is a different topic. Here are a few code snippets I use for a similar task. The basic idea is, when reading the objects that will be displayed, to include the database id with the object. So, if I read a list of products, the the domain class Product will have an id field that gets set with the database id when reading it.
To get the domain object displayed at a specific list position (e.g. the one where a user hit a delete button), the code fragment is.
public void onClick(View view) {
Product product = (Product) ProductList.this.products.get(ProductAdapter.this.listView.getPositionForView((View) view.getParent()));
... now do whatever is necessary to delete the product, probably
calling a DAO class that deletes the object based on its id,
not the list position
ProductAdapter.this.notifyDataSetChanged();
}
Solved this by removing the row in the database by the text of the TextView in the ListView instead of removing by the position of the TextView.
Now looks like this:
//Erasebutton listener
final Button eraseButton = (Button) findViewById(R.id.eraseButton);
assert eraseButton != null;
eraseButton.setOnClickListener(new View.OnClickListener() { //erasebutton onclick
public void onClick(View eraseButton) {
SparseBooleanArray checked = questionList.getCheckedItemPositions();
for(int i = questionList.getCount() - 1; i >= 0; i--)
{
if(checked.get(i)) {
//What to do with selected listitems
TextView tv = (TextView) questionList.getChildAt(i).findViewById(R.id.checkedTextView1);
db.removeData(tv.getText().toString());
}
}
checked.clear();
Cursor newCursor = db.getData();
adapter.swapCursor(newCursor);
}
});
And removeData function now looks likte this:
public boolean removeData(String question) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, COL_QUESTION+"='"+question+"'", null);
return true;
}
Currently I can check/uncheck the checkboxes by groupPosition and childPosition, and it's working fine. I save the groupPosition and childPosition to the SQLite Database.
When I added the delete option, my checkbox checked states are off/messed up.
For example, I have the following:
Group1,
Child1, Child2, Child3
I check all 3 of them and save the checked positions to the SQLite Database.
The checked positions would be 0,0 and 0,1 and 0,2 in the Database.
After I deleted Child1,
Child2 becomes position 0, Child3 becomes position 1 which would mess up the checked states.
I am trying to find a way to save the group name and child name instead of the positions to the SQLite Database, then load those names in Oncrete method.
MainActivity:
if(category_array.get(groupPosition).subcategory_array.get(childPosition).selected) {
category_array.get(groupPosition).subcategory_array.get(childPosition).selected = false;
try{
MySQLITE_DATABASE.deleteRows(groupPosition, childPosition);
}
catch (Exception e) {}
}
else
{
category_array.get(groupPosition).subcategory_array.get(childPosition).selected = true;
MySQLITE_DATABASE.addRow(groupPosition, childPosition);
}
Adapter code:
private List<Category> mGroupCollection;
if(mGroupCollection.get(groupPosition).subcategory_array.get(childPosition).selected) {
childHolder.checkBox.setBackgroundResource(R.drawable.checkbox_checked);
} else {
childHolder.checkBox.setBackgroundResource(R.drawable.checkbox_unchecked);
}
Date Holder Classes:
public class Category {
public String category_name = null;
public String cat_SelectedChildCount_name;
public ArrayList<SubCategory> subcategory_array = new ArrayList<SubCategory>();
}
//==============================
public class SubCategory {
public String subcategory_name = null;
public boolean selected = false;
}
I want to save the group name and child name instead of positions to the SQLite Database and then load them in OnCreate method.
I have tried this but it is not working:
String Group_Name = category_array.get(Integer.parseInt(groupPosition)).category_name;
String Child_Name = category_array.get(Integer.parseInt(groupPosition)).
subcategory_array.get(Integer.parseInt(childPosition)).subcategory_name;
if(category_array.get(Group_Name).subcategory_array.get(Child_Name).selected) {
category_array.get(Group_Name).subcategory_array.get(Child_Name).selected = false;
MySQLITE_DATABASE.DeleteRow(Group_Name, Child_Name);
}
else {
category_array.get(Group_Name).subcategory_array.get(Child_Name).selected = true;
MySQLITE_DATABASE.AddRow(Group_Name, Child_Name);
}
I know that I need to change the code in the adapater, data holder classes, and mainactivity in order to make it work, but I am out of ideas. I have been thinking and thinking, but nothing works...
Can someone please please guide me on this?
I am sorry for the long code.
Thank you and thank you.
Try any of the following if it suit's your requirement.
If you want to use the position strictly (May be there is no unique option)
Keep the DB design like
| id | parent_position | child_position |
Assume you have N childs. If you delete a child (Suppose it's 0). do this
Update all the child's with (child_position = child_position - 1) whose position is greater than
the deleted child of the parent. So the position remains unchanged.
Personally i would suggest don't use the position if a delete option is there. Option that i found, But don't know your use case
If you are loading the list from the database use the database primarykey as the key to save it in the SQLite database on selection/unselection. In this case you don't want to know the parent position as well.
I am learning how to create a spinner that loads dropdown from SQLite. I have an UI that consists of a spinner and a table. If user clicks spinner, the table's content will load according to the database based on the selected ID on spinner. If name not selected, it will load all contents in table.. However I can't find the way how to make the table reload based on the ID / name selected on spinner. Anyone can guide me?
The table itself is a joined table, which has following structure:
Table A : ID_Person | Name | Age
Table B : ID_Account | ID_Person | Amount
Spinner shows Person's name. Meanwhile the table will show the following structure:
Name | Age | Amount
My code for spinner:
public List<String> getAllDealers()
{
List<String> contentdealer = new ArrayList<String>();
// Select All Query
String selectQuery = "SELECT * FROM " +Dealer_TABLE;
cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
contentdealer.add(cursor.getString(1));
} while (cursor.moveToNext());
}
// closing connection
return contentdealer;
}
Here is how I build my Table for looping:
Cursor c = in.getViewInfo(); //method in db consists of query that i want table show
int rows = c.getCount();
int cols = c.getColumnCount();
c.moveToFirst();
// outer for loop
for (int i = 0; i < rows; i++)
{
//looping all rows based .getCount()
//looping all columns
for (int j = 0; j < cols; j++)
{
}
}
in.close();
See a similar but not exact same answer here
https://stackoverflow.com/a/11920785/1116836
I believe what you want is
spinner.setOnItemSelectedListener(new OnItemSelectedListener()
{
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id)
{
Toast.makeText(context, "item selected, load some sql", Toast.LENGTH_LONG).show();
// position should match the index of the array in the items list you used for which item is selected, or here you could do
String selected = spinner.getSelectedItem().toString();
// or
String anotherway = spinner.getItemAtPosition(position).toString();
if (selected.equals("what ever the option was")) {
}
}
#Override
public void onNothingSelected(AdapterView<?> parentView)
{
Toast.makeText(context, "nothing selected, load some sql", Toast.LENGTH_LONG).show();
}
});
likely to be able to select nothing, you will have to insert a view with no text, and allow that to be selected.
onNothinSelected is more for when a list is modified, or the currently selected item becomes unselected, e.g. when it is in in between selections it may call this method.
Callback method to be invoked when the selection disappears from this
view. The selection can disappear for instance when touch is activated
or when the adapter becomes empty.
So basically, when a new item is selected, call a method that loads some sql rows, clear your table and then display the new data.
EDIT: for comment
What you are trying to do is an event drive function. When someone selects a new option in the spinner, it is an event. You listen for this event by, as I showed above, implementing the OnItemSelectedListener().
One you implement this, you can find out what item is selected, as soon as it happens. Once a new item is selected, you need to determine what that item means you should do.
Once you have figured that out, run your SQL statement and query your database, load the data, set it in the adapter and then the user will see it.
If you are using a ListView, which you should be, then you need to clear the adapter to the ListView, and then add the new items.
You need to research ArrayAdapter, BaseAdapter, ViewHolder pattern, and ListView's.
A quick google search will have you up and running in no time.
I have a toggle button which saves data to SQLite table when checked and deletes data from table when unchecked. And I am populating a listview from the same table. So when I uncheck the toggle button, am able to delete the records one by one except the one last record, which shows up in listview.
But when I check the toggle button to insert new record, the one last record in listview is replace by new record.
Below is the toggle button code
if(bookmark.isChecked()){
// Insert record
}
}else{
dbAdapter.write();
dbAdapter.deleteSingleBookmark(urlHost1);
dbAdapter.close();
}
Sqlite code
public boolean deleteSingleBookmark(String bookmarkHost2) throws SQLException{
return (int) db.delete(BOOKMARKS_TABLE, BOOKMARK_NAME + "=?", new String[] { bookmarkHost2 }) > 0;
}
I tried ">=0" in deleteSingleBookmark method, but that doesn't work. My issue is similar to this, but am not using cursor.
How do I delete this one last record from the listview?
You need to operate with data in ListViewAdapter which you provided for your ListView.
Delete needed data from adapter and call method:
yourAdapter.notifyDataSetChanged();
try
public boolean deleteSingleBookmark(String bookmarkHost2) throws SQLException{
return (int) db.delete(BOOKMARKS_TABLE, BOOKMARK_NAME + "="+bookmarkHost2, null) > 0;
}
I've been working on this application but have come across a problem that I have been unable to figure out. I have a listview that is populated with the contents from an adapter, and each row has their specific information (Uniform). The problem comes when I try to retrieve the value of a checkbox that is found in that particular row.
The code in question is below:
I build an AlertDialog object so I can get my information from the user. My layout code consists of a LinearLayout in horizontal orientation with 3 elements an image, text, check box. I build my AlertDialog with R.layout.listview_layout, which is a custom layout that I made.
One thing I tried to do is get the CheckBox View from the adapter, however; when I look at it via cb.isChecked(), no matter what row i'm on its always unchecked (aka false). In order to debug this further I took the same adapter and retrieved the text via the same methodology and it returned specific information about that row, as it should.
Any ideas how I can handle this?
Simply Put:
I would just like to get the value of the CheckBox at each given row
c = help.returnContacts();
AlertDialog.Builder ab = new AlertDialog.Builder(this);
ab.setTitle("Select contacts");
final SimpleCursorAdapter adapter = new SimpleCursorAdapter(
getApplicationContext(), R.layout.listview_layout, c,
new String[] { ClientOpenDbHelperUtility.COL_NAME,
ClientOpenDbHelperUtility.COL_SEL }, new int[] {
R.id.txt_name, R.id.cb_select });
ab.setAdapter(adapter, null);
ab.setPositiveButton("Confirm", new Dialog.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Cursor c = adapter.getCursor();
for (int i = 0; i < adapter.getCount(); i++) {
CheckBox cb = (CheckBox) adapter.getView(i, null, null)
.findViewById(R.id.cb_select);
TextView t = (TextView) adapter.getView(i, null, null)
.findViewById(R.id.txt_name);
Log.d("DEBUG", "Checked = " + cb.isChecked());
Log.d("DEBUG", "Message = " + t.getText().toString());
if (cb.isChecked()) {
help
.updateSelection(
c
.getColumnIndex(ClientOpenDbHelperUtility.COL_UID),
true);
} else {
help
.updateSelection(
c
.getColumnIndex(ClientOpenDbHelperUtility.COL_UID),
false);
}
}
c.close();
help.closeAll();
}
});
ab.show();
}
Thanks for reading!
You shouldn't call getView directly. Doing so generates a fresh view (or recycles and overwrites an old one) based on the contents of your database.
Also, once your rows scroll off the top or bottom of the screen they will be recycled for use in new rows that appear. All of your data but the currently visible rows are most likely to have already vanished by the time your onClick method gets called.
You have two options:
Persist changes immediately to the database - set an OnClickListener on your checkbox or on the row and update your database on each click event.
Save changes to an instance variable and then apply later - define a Map<Integer, Boolean> changes instance variable for your activity and call changes.put(position, isChecked) whenever there is a click. Then when your user clicks "Apply" or whatever your onClick is, go through changes and persist each one to the database. It's basically the same as what you have now except you would be using a stable object to store the unsaved changes.