I am trying to populate a Spinner in an Android dialog. When the user clicks a button, a dialog pops up and I load the layout from an XML file. Now I am trying to populate that Spinner from a SQL query. I have searched all over and cannot figure out what the problem is. I can loop through the Cursor and add each value to an ArrayAdapter and then use that as the list for the spinner but that doesn't come with the _id's from the database. I have done this before using a SimpleCursorAdapter and I have even copied and pasted my old code exactly and still it isn't working. Any help would be much appreciated.
My Dialog code:
private void displayNewInteractionDialog() {
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.mm_new_dialog);
dialog.setTitle(R.string.mm_new_dialog_title);
dialog.setCancelable(true);
final Spinner spinner = (Spinner) dialog.findViewById(R.id.mm_spinner);
DatabaseInterface db = new DatabaseInterface(this);
db.open();
Cursor c = db.getNames();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_spinner_item,
c,
new String[] {DatabaseInterface.KEY_ID, DatabaseInterface.KEY_NAME},
new int[] {android.R.id.text1});
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
c.close();
db.close();
dialog.show();
}
Here is the code that returns a Cursor in my DatabaseInterface class:
public Cursor getNames() {
return db.query(DATABASE_TABLE_4, new String[] {DatabaseInterface.KEY_ID, DatabaseInterface.KEY_NAME}, null, null, null, null, null);
}
I know this will work I am just missing something apparently. I know that I could load the Spinner with the list of names from the ArrayAdapter that I stated above and also populate an array with the ID's from the query and when the user selects an item I could just grab the corresponding one from the array of ID's... But I know the SimpleCursorAdapter will work I just can't seem to figure it out and I'm not giving up until I do haha. Thanks in advance for any help.
Well looks like I am dumb haha... For some reason or another, probably from just trying numerous things and then forgetting to remove parts that I had added. I just removed c.close(); and now everything is fine. I remember adding that as I was trying to figure things out and I must've fixed the problem somewhere else and then didn't realize it because this line was still in there. Since I am not actually doing anything with the Cursor other than passing it to a function, it doesn't need to be closed. Anyhow all is good, I knew it was going to be something stupid. Like usual.
Related
I have looked at the plethora of similar topics for the past couple days but none seem to help my actual situation or maybe it's just my inexperience.
I have a simple application that performs CRUD operations. I can successfully enter new rows into the table as well as delete them, however something is wrong with my update code and I can't find why. What has me puzzled is it worked once, then never did again regardless if I create new entries or delete the database entirely and start again. Isolating what I think the relevant code would be the operation flow is as follows.
The individual items are inside a RecyclerView and are sent from an inner class to the activity to be edited and updated:
public void onBindViewHolder(#NonNull ContactViewHolder holder, int position) {
final String contactName = mCursor.getString(mCursor.getColumnIndex(ContactEntry.COLUMN_NAME));
final int contactNumber = mCursor.getInt(mCursor.getColumnIndex(ContactEntry.COLUMN_PHONE_NUMBER));
final String contactMail = mCursor.getString(mCursor.getColumnIndex(ContactEntry.COLUMN_EMAIL));
final int currentPosition = position;
holder.mEditContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, ContactUpdate.class);
intent.putExtra(CONTACT_POSITION, currentPosition);
intent.putExtra(EXTRA_NAME, contactName);
intent.putExtra(EXTRA_PHONE, contactNumber);
intent.putExtra(EXTRA_MAIL, contactMail);
mContext.startActivity(intent);
}
});
Then I get them in the retrieving class and organise the values into the appropriate EditText views. I'm sure there is a more efficient way but I'm still learning:
Intent intent = getIntent();
mPosition = intent.getIntExtra(ContactRecyclerAdapter.CONTACT_POSITION, 0);
mContactName = intent.getStringExtra(ContactRecyclerAdapter.EXTRA_NAME);
mContactPhone = intent.getIntExtra(ContactRecyclerAdapter.EXTRA_PHONE, 0);
mContactMail = intent.getStringExtra(ContactRecyclerAdapter.EXTRA_MAIL);
mUpdateName.setText(mContactName);
mUpdatePhone.setText("" + mContactPhone);
mUpdateMail.setText(mContactMail);
Lastly my method to update the row:
private void updateData() {
String name = mUpdateName.getText().toString();
String getPhone = mUpdatePhone.getText().toString();
int phone = Integer.parseInt(getPhone);
String mail = mUpdateMail.getText().toString();
SQLiteDatabase db = new ContactOpenHelper(this).getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ContactEntry._ID, mPosition);
values.put(ContactEntry.COLUMN_NAME, name);
values.put(ContactEntry.COLUMN_PHONE_NUMBER, phone);
values.put(ContactEntry.COLUMN_EMAIL, mail);
String selection = ContactEntry._ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(mPosition)};
db.update(ContactEntry.TABLE_NAME, values, selection, selectionArgs);
db.close();
startActivity(new Intent(this, ContactList.class));
}
What is happening is the row is not being updated. Currently I have three mock entries entered. I put a break point at the update() line to try and find out what is happening. The original name for the this entry is "ted" and it's the third in the list. If I edit the EditText field and run the updateData() method, when the break point is hit it correctly shows the edited value as well the correct position of 2. However the database doesn't actually update. I am clearly misunderstanding how something works here.
To avoid bloat I have only included what I think is pertinent, but if anymore info is required then I'm happy to add.
Lastly here is a screen shot of the debugger at the break point showing what I perceive to be the correct information and where I'm completely confused as to why it is not working (I added a bunch of g's on the end of the name "ted" just to test if it would work).
Chnage your call to update as below
int count = db.update(ContactEntry.TABLE_NAME, values, selection, selectionArgs);
where count shows the number of the rows afftected with the update function, this would help you know exactly if there was any updated row or not.
Note :-We use like when, sometimes, you don’t know exactly the complete keyword that you want to query. For example, you may know that your most favorite song contains the word,elevator but you don’t know exactly the name.
If you know the exact value try to use:-
String selection = ContactEntry._ID + " =? ";
String selection = ContactEntry._ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(mPosition)};
Update this above code to this below code
String selection = ContactEntry._ID + " = ?";
String[] selectionArgs = { String.valueOf(mPosition)};
You want to update an exact row. But 'LIKE' keyword mostly uses for searches.
Besides, You are opening your activity when you update your data. Update or insert in database takes some time. When your next activity start, database may not finish its write operation. It could lead you to see the previous data. Make sure your database is updated and then update the view.
See your database from emulator that database has the new value or not. Then do the further work.
Try to delete you _Id from contentValues:
//values.put(ContactEntry._ID, mPosition);
I think you can't change PRIMARY_KEY, you say what line you want to update in:
String[] selectionArgs = { String.valueOf(mPosition)};
I have now solved this particular problem and the answer was quite simple and a little embarrassing. I was trying to use the cursor position for the row ID not realising that the database isn't using a zero-base index like the cursor, hence the primary key was not matching.
As I am using a RecyclerView I added the following line to my onBindViewHolder and passed the variable to my update activity which then could be used in the selectionArgs
final long id = mCursor.getLong(mCursor.getColumnIndex(ContactEntry._ID));
So, if I create an AlertDialog like so:
AlertDialog.Builder b = new AlertDialog.Builder();
b.setItems(MyStringArray, MyListener);
b.create().show();
And then I want to update the items in the list, i.e. MyStringArray has changed to have more or fewer items. I can't seem to find a way to do this. So far, I've tried getting the ListView from the AlertDialog, but I can't seem to get .setAdapter to work. Is this the right approach, or is there a better way to do this?
I haven't tried this out myself, but from all the other apps I've built I'm pretty sure this will solve your problem.
Instead of using setItems, try using the setAdapter() method and pass in an ArrayAdapter that has been initialized with the data from your Array of String. Then, when you know that the data has changed, you can use getListView() to get your View object and from there call getAdapter() so that now you're working directly with the dataset. You can clear it, and re-initialize it if you like, or just add / remove the items as you like. From the adapter object, if you call notifyDataSetChanged() it should trigger a re-draw using the new data set that you just supplied to the adapter.
Hope that helps you out. Let me know if it doesn't.
DSC
If you are like me and you would like to use default adapter for example for multichoice items, then there is also a way.
Just as with any other adapter just update the string array object, get adapter from the dialog instance, cast it to appropriate adapter and invalidate it.
AlertDialog.Builder b = new AlertDialog.Builder();
b.setItems(MyStringArray, MyListener);
AlertDialog instance = b.create();
instance.show();
// Later when you need to update
MyStringArray[0] = "puf";
ListView list = instance.getListView();
// Now according to whether you used cursor or array for supplying items to the builder
// you have to cast adapter to either CursorAdapter or ArrayAdapter
ArrayAdapter adapter = (ArrayAdapter)list.getAdapter();
adapter.notifyDataSetChanged();
You can find out more here.
This is how I did it in Kotlin:
AlertDialog.Builder(context).apply {
val actions = arrayListOf("aa", "bb")
val onItemClickListener = DialogInterface.OnClickListener { dialog, which ->
// code
}
val adapter = ArrayAdapter(requireContext(),
android.R.layout.simple_list_item_1, actions)
setAdapter(adapter, onItemClickListener)
executeGetRequest() {
actions.add("cc")
adapter.notifyDataSetChanged()
}
}.show()
I'm trying to filter the contacts list by modifying the selection of my cursor when an OnTextChange happens in my EditText. The problem: the list stays as it is, i.e. it does not get updated as per the filter. What am I doing wrong? I suspect it's my sql query (specifically GLOB part)?
digitsText.addTextChangedListener(new TextWatcher(){
public void onTextChanged(CharSequence s, int start, int before, int count){
filterText = digitsText.getText().toString();
WHERE_CONDITION = ContactsContract.Data.DATA1 + " GLOB '*" + filterText + "*'";
cursor = getContentResolver().query(URI, PROJECTION, WHERE_CONDITION, null, SORT_ORDER);
startManagingCursor(cursor);
setListAdapter(adapter);
}
});
While you generate a new Cursor, you do not actually do anything with it. You need to either:
call swapCursor() on your CursorAdapter, if you are on API Level 11 or higher
call changeCursor() on your CursorAdapter (which may be the better option anyway, if you will not be needing the old Cursor, as changeCursor() will close it for you)
create a new CursorAdapter and call setListAdapter() using the new adapter
I am working in Android. I want to design a spinner of song categories.
This is my code:
public Spinner spinner_category_forSong;
String[] arr_Category={"Select","sad","dj","rock"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this,android.R.layout.simple_spinner_item,arr_Category);
spinner_category_forSong = (Spinner)findViewById(R.id.Spinner_category_forUpload);
spinner_category_forSong.setPrompt("Music Category :");
spinner_category_forSong.setAdapter(adapter);
But whenever I run my project, a null pointer exception is created in spinner_category_forSong.setPrompt("Music Category :"); and spinner_category_forSong.setAdapter(adapter);.
Please tell me what mistake I have made in this code.
From your exception it seems that findViewById(R.id.Spinner_category_forUpload) returns null. My guess is that you didn't call setContentView() prior to your method calls.
From the code sample your class structure is not clear. Are some lines inside onCreate()?
try after setting adapter spinner_category_forSong.setAdapter(adapter); before spinner_category_forSong.setPrompt("Music Category :");
private void datafill()
{
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);
/* JournalRowId is the row id from the first database containing all journal names
All notes are kept in database 2. I want only the notes that correspond to each
journal to be listed, KEY_HOMEID is the non visible field that shows where
each note came from.
*
*/
if (editjournalDbAdapter.KEY_HOMEID == journalRowId){
String[] from = new String[]{editjournalDbAdapter.KEY_HEIGHT};
int[] to = new int[]{R.id.detail1};
}
//Error here "from" and "to" are not defined outside of if statement
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.journaldetailrow, notesCursor, from, to);
setListAdapter(notes);
}
"from" and "to" only exist within the scope of the if() statement. Wouldn't make much sense otherwise anyway - even if they did, their contents would be undefined (or, in case of Java, null) and immediately crash your app.
I have no idea what you're trying to accomplish, but you probably want the bottom two statements inside the if() block as well.