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.
Related
I've done a list that shows titles, when i click on an item is opened an activity that shows the description of the element; i'm getting this description using the id of the element.
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String descrizione=mydb.getDescription(id+1,titolo.getText().toString());
}
This is the method in my database:
public String getDescription(long id,String formulario)
{
String descrizione="NADA";
SQLiteDatabase db= this.getReadableDatabase();
Cursor res = db.rawQuery( "select * from "+formulario+" where id="+id+"", null );
if(res!=null && res.getCount()>0){
res.moveToFirst();
descrizione = res.getString(res.getColumnIndex("Descrizione"));
res.close();
}
return descrizione;
}
THE PROBLEM: when i delete an element all the description result shifted forward. I don't know if the problem is with the cursor, the item's id acquisition or with the delete method... any help is valued
This is my delete method:
public Integer deleteFormula (String formula, String formulario)
{
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(formulario, "Formule = ? ", new String[] { formula});
}
First off, when you want to show database data in a ListView, you should use CursorAdapter to bind database data with your ListView. From the code you've posted, can't tell whether and how it's been implemented. If you have any doubts about it I suggest you look into this article which explains this subject very well https://github.com/codepath/android_guides/wiki/Populating-a-ListView-with-a-CursorAdapter
Secondly, when you successfully bind the data to your ListView, then in onItemClick method you can use the second parameter which is View and represents the clicked ListView row , to retrieve the data that is shown in that row.
Thirdly, when you delete a row from your database table, you should synchronize your ListView by getting a new cursor and calling your CursorAdapter changeCursor method with new cursor as argument.
This is just a rough sketch, but I hope it will help at least a little bit.
Cursor adapter would be the optimal solution. But if you want to stick with the same code when you delete a row from your database table you must ensure that you also get the updated list of data from your database.
And also you don't have to add + 1 to this code. If you have to add + 1 it means you're doing things wrong.
String descrizione=mydb.getDescription(id+1,titolo.getText().toString());
This would work well if you are just constantly updating your list with the data from your database whenever there are changes, and id doesn't represent the databaseID as it represents the ID of the view within the adapter.
Your issue is using position to determine id in :-
String descrizione=mydb.getDescription(id+1,titolo.getText().toString());
At first, assuming 3 columns inserted:-
First column has an id of 1, 2nd 2 and 3rd 3. So initially if rows are sorted according to id (good chance of this happening but no guarantee) then position 0 (first row displayed) + 1, will display data for id 1, position (2nd item in the List) 1 will show data for id 2 etc and all looks good.
However if you delete id 2 then:-
The 1st item in the list will display data from id 1 and position 0 still equates to id 1.
However the 2nd Item in the list will display data from the table for row id 3 BUT position 1 + 1 = 2 so the wrong id is calculated.
In short you cannot use position to correlate to the id.
You need to somehow get the appropriate row. Perhaps the easiest solution is to use a CursorAdapater, then id will be the id (column name must be _id).
I display the user data from SQLite database using a custom CursorAdapter.
Each ListView item is actually a layout with many TextViews.
in the CursorAdapter.bindView() method I get database data from the Cursor, and display their modified, prettier versions to the user. Here's what I mean:
public void bindView(View view, Context context, Cursor cursor) {
//get listview items Views
TextView dayTextView = (TextView)view.findViewById(R.id.listview_item_day);
//...
//get data from cursor
int day = cursor.getInt(1);
//...
//display data nicely to the user
String sDay = "Day number " + String.valueOf(day) " was a very nice day";
dayTextView.setText(sDay);
}
I want that when the user long clicks an item (I'll use OnItemLongClickListener for that), the item will be deleted (easy peasy) but I also want to delete the day record from the database.
When the ListView item gets clicked, I have the next parameters supplied to me (in OnItemLongClickListener):
AdapterView<?> adapterView, View view, int position, long id
How do I get to the database record from all these parameters? I could use TextView.getText() and apply some string manipulation methods to the result (remember I added strings to the data before setting it in ListView), but I feel like there's another, more clever way.
You might use a List<Integer> days = new Arraylist<>(); to keep days you are modifying and so the index of the list alway will be same as position and you can get your day content by days.get(position) and get item from your database.
you should define your list out of bindView
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;
}
I have a problem on Android Spinner.In my application I created two Spinner on main layout. 'State' Spinner and 'District' Spinner. All the data on Spinner are stored in SQLite database. I want do display list of 'District' on second spinner depending on selection of particular 'State' in the first spinner.
Example: Suppose when I select Karnataka in the first spinner then application first retrieve all the district from SQLite database related to karnataka state and then it display on second Spinner.
For this I do all the database activity correctly means creating two table 'state' and 'district' in which one column in district table is foreign key which is refereed to one of the primary key of 'state table'
db.execSQL("create table "+STATE_TABLE+" ("+
STATE_ID+" integer primary key autoincrement not null, "+
STATE_NAME+" text"+")");
db.execSQL("create table "+DISTRICT_TABLE+" ("+DISTRICT_ID+
" integer primary key autoincrement not null,"+DISTRICT_NAME
+" text,"+STATE_ID+" integer, FOREIGN KEY("
+STATE_ID+") REFERENCES "+STATE_TABLE
+"("+STATE_ID+")"+")");
Now in the Activity Class:
spinnerState = (Spinner)findViewById(R.id.spinner1);
spinnerDistrict = (Spinner)findViewById(R.id.spinner2);
stateList = new ArrayList<String>();
districtList = new ArrayList<String>();
Suppose all the data are all ready stored in database.
Now I need to retrieve all the 'State' data from database and add it in the statelist which is ArrayList.
Cursor stateCursor = database.query(STATE_TABLE, new String[]{STATE_ID, STATE_NAME},
null, null, null, null, STATE_NAME);
stateCursor.moveToFirst();
if(! stateCursor.isAfterLast()){
do{
int id = stateCursor.getInt(0);
String stateName = stateCursor.getString(1);
stateList.add(stateName);
}while(stateCursor.moveToNext());
}
stateCursor.close();
after this I create one ArrayAdapter and put this state list into this.
spinnerState.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, stateList));
Next i put the following code in the activity class:
spinnerState.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View v,
int pos, long id) {
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
Now My problem is here:
How I get the StateId for executing the select query for taking all the district related to particular state in database.
How the adapter will generate for District.
where I put all these code.
Here what I need creating the districtList after getting the value from state Spinner.
Similar Question which asked earlier in this website, what they do:
they already create two adapter for two spinner and then apply setOnItemSelectedListener.
Please Help me because here my mind totally stop working.
I refer lot of book and website but not they even mention these type of problem.
I see a couple of solutions here:
Option 1:
Instead of declaring stateList as an ArrayList<String>, create a custom POJO StateInfo and designate stateList as ArrayList<StateInfo>
public class StateList {
private int id;
private String stateName;
//Constructors, getters and setters
}
Then,
if(! stateCursor.isAfterLast()){
do{
int id = stateCursor.getInt(0);
String stateName = stateCursor.getString(1);
stateList.add(new StateInfo(id, stateName));
}while(stateCursor.moveToNext());
}
Now, you can do this:
public void onItemSelected(AdapterView<?> parent, View v,
int pos, long id) {
int id = stateList.get(pos).getId();
//Use This ID to construct your next SQLite query; and populate the district spinner.
}
If you do this, you will have to create a custom ArrayAdapter and implement the getView() method. Look at the Android docs for how to do this.
Option 2:
Why do you even need the stateID? I suppose you can write a Query to get the districts list given a state Name only. In that case, you can retain the stateList as an ArrayList<String> and you don't even need the StateInfo class at all. Just do this:
public void onItemSelected(AdapterView<?> parent, View v,
int pos, long id) {
String stateName = stateList.get(pos);
//Use this name to construct your next SQLite query; and populate the district spinner.
}
For problem 1:
You just need to keep track of which state user selects into the spinner and according to its position,you have to find its related id.then you can query for district accordingly.obviously you will have to use onItemSelectedListener of that spinner to get position of state selected.
For problem 2:
You need to make a method in helper class which accepts stateId(which you would compute as i said above) and return you according district names in a String array.So in your main activity,in onItemSelectedListener of a state spinner,you will have to grab that string array and prepare a adapter for the same. There,you will have to set adapter to your district spinner.
This will always give you your district spinner updated with what user selects in state array.
For problem 3:
Almost all code would be in onItemSelectedListener of your state spinner only.Just a method to fetch related district names would be in your helper class.
is it possible to programatically access specific rows in a list of CheckedTextViews to change the state of their textboxes?
my program has a listview which has several CheckedTextViews which the user can press to toggle state.
I want to save the state of the checkboxes when the user leaves the activity, so I have in my onPause method:
public void onPause(){
super.onPause();
SparseBooleanArray positions;
positions = listView.getCheckedItemPositions();
ListAdapter items = listView.getAdapter();
int j = items.getCount();
ArrayList<Long> ids = new ArrayList<Long>();
for (int k =0; k < j;k++){
if(positions.get(k)==true){
ids.add(items.getItemId(k));
}
}
this.application.getServicesHelper().open();
this.application.getServicesHelper().storeServices(ids,visit_id);
this.application.getServicesHelper().close();
}
which very simply iterates the list view, adds the checked items to an ArrayList and then saves that list of ids to the database.
My problem lise in trying to reset the list once a user goes back to that activity.
so far in my onStart method, I recall the checked items from the database, but I do not know how to march the ids returned to the listview elements. can I do something like:
listView.getElementById(id_from_database).setChecked?
I know I cant use getElementById but I have it here to show what I mean
Thanks in advance
Kevin
You can call
listView.setItemChecked(int position, boolean value)
This is what Ive ended up doing.. but it seems like a complete hack.
Basically I have to set up a double for loop.. one to iterate through my list elements, and one to iterate through the cursor that I have retreived my check list state (a simply array of ids of elements that were checked when state was last saved)
my outer for iterates through the list elements checking each id against a loop through the list of ids to be set as checked. if they equal each other then set that item as checked.
// mAdapter is contains the list of elements I want to display in my list.
ServiceList.this.setListAdapter(mAdapter);
// Getting a list of element Ids that had been previously checked by the user. getState is a function I have defined in my ServicesAdapter file.
Cursor state = ServiceList.this.application.getServicesHelper().getState(visit_id);
int checks = state.getCount();
int check_service;
int c = mAdapter.getCount();
if(checks>0){
state.moveToFirst();
for (int i=0; i<checks; i++) {
// set check_service = the next id to be checked
check_service = state.getInt(0);
for(int p=0;p<c;p++){
if(mAdapter.getItemId(p)==check_service){
// we have found an id that needs to be checked. 'p' corresponds to its position in my listView
listView.setItemChecked(p,true);
break;
}
}
state.moveToNext();
}
}
ServiceList.this.application.getServicesHelper().close();
Please tell me there is a more efficient way of achieving this!!
Thanks
Kevin