问题
I have a SQLite Database with is populating my Spinner. The "add" functionality it's working good! What I wanna do is when user clicks in on spinner item he can change the following field and update in the Database
My Spinner database
public class SpinnerDatabase extends SQLiteOpenHelper{
private SQLiteDatabase db;
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "spinnerDB";
private static final String TABLE_LABELS = "labels";
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
public SpinnerDatabase(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CATEGORIES_TABLES = "CREATE TABLE " +
TABLE_LABELS + "(" + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"+
KEY_NAME + " TEXT)";
db.execSQL(CREATE_CATEGORIES_TABLES);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_LABELS);
onCreate(db);
}
public void insertLabel(String label){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME,label);
db.insert(TABLE_LABELS,null,values);
db.close();
}
public List<String> getAllLabels(){
List<String> labels = new ArrayList<String>();
String selectQuery = "SELECT * FROM "+ TABLE_LABELS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery,null);
if (cursor.moveToFirst()){
do{
labels.add(cursor.getString(1));
}while (cursor.moveToNext());
}
cursor.close();
db.close();
return labels;
}
public void updateSpinner (int id, String label){
ContentValues values;
String where;
db = this.getWritableDatabase();
where = KEY_ID + " = " +id;
values = new ContentValues();
values.put(KEY_NAME,label);
db.update(TABLE_LABELS,values,where,null);
db.close();
}
}
The problem is when I click the button to update, it doesn't do anything! And just update the other item (if I have more the one). This is my method in my fragment that list all the entries:
private void loadSpinnerData (){
SpinnerDatabase db = new SpinnerDatabase(getActivity().getApplicationContext());
List<String> labels = db.getAllLabels();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_spinner_item,labels);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
And here the button save that i'm trying to do the update:
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = editText.getText().toString();
if(name.length()>0 && name != null){
int spinnerValue = spinner.getSelectedItemPosition();
SpinnerDatabase db = new SpinnerDatabase(getActivity().getApplicationContext());
db.updateSpinner(spinnerValue,name);
}
});
回答1:
Your issue, is that you are using the Spinner's selected position (0,1,2 etc) as the row's id. The first row id will be 1, then 2, etc (probably but NOT CERTAINLY i.e. delete a row for some reason and you have a gap in the sequence).
As such what you are currently experiencing is a difference of 1 between row id and spinner position, so either nothing or another row is being updated.
You either need to employ some method of working out the row id to spinner position (e.g a second array that has the respective id for the same index of the first array), or to, what I'd do is, take advantage of the flexibility of a CursorAdpater
, such as SimpleCursorAdapter
and then use spinner.getSelectedItemId()
instead of spinner.getSelectedItemPosition()
.
To use A CursorAdapter, you will need a row called _id (e.g. change private static final String KEY_ID = "id";
to public static final String KEY_ID = "_id";
)
Note! I'd also suggest changing, as I have above, your private statics
to public statics
).
Also to use a CursorAdapter, you will need a Cursor. The following method in SpinnerDatabase.java would suffice.
public Cursor getAll() {
db = this.getWritableDatabase();
return db.query(TABLE_LABELS,null,null,null,null,null,null);
}
The following could be used to setup the adpater:-
csr = dbhlpr.getAll();
sca = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
csr,
new String[]{SpinnerDatabase.KEY_NAME},
new int[]{android.R.id.text1},0);
spinner.setAdapter(sca);
Note! the use of SpinnerDatabase.KEY_NAME
, this is an example of why I suggest 'public static' as opposed to private static
.
There are sublte differences for the SimpleCursorAdpater;
- 3rd paramter is the Cursor,
- 4th is a String array of the column names in the cursor to be dis0played(should match 5th parameter),
- 5th is the id's of the views into which the data is placed (for simple_list_item_1 use 1 column name along with android.R.id.text1 as above).
and when it comes to the update use spinner.getSelectedItemId()
for the row id.
Working Example (assumes rows have data)
SpinnerDatabase.java
public class SpinnerDatabase extends SQLiteOpenHelper {
private SQLiteDatabase db;
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "spinnerDB";
private static final String TABLE_LABELS = "labels";
private static final String KEY_ID = "_id";
public static final String KEY_NAME = "name";
public SpinnerDatabase(Context context) {
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CATEGORIES_TABLES = "CREATE TABLE " +
TABLE_LABELS + "(" + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"+
KEY_NAME + " TEXT)";
db.execSQL(CREATE_CATEGORIES_TABLES);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_LABELS);
onCreate(db);
}
public void insertLabel(String label){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME,label);
db.insert(TABLE_LABELS,null,values);
}
//Defunct
public List<String> getAllLabels(){
List<String> labels = new ArrayList<String>();
String selectQuery = "SELECT * FROM "+ TABLE_LABELS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery,null);
if (cursor.moveToFirst()){
do{
labels.add(cursor.getString(1));
}while (cursor.moveToNext());
}
cursor.close();
return labels;
}
public void updateSpinner (long id, String label){
ContentValues values;
String where;
db = this.getWritableDatabase();
where = KEY_ID + " = " +id;
values = new ContentValues();
values.put(KEY_NAME,label);
db.update(TABLE_LABELS,values,where,null);
db.close();
}
public Cursor getAll() {
db = this.getWritableDatabase();
return db.query(TABLE_LABELS,null,null,null,null,null,null);
}
}
Activity SO46330096Activity.java
public class SO46330096Activity extends AppCompatActivity {
SpinnerDatabase dbhlpr;
Spinner spinner;
Button editbutton;
EditText spinneritem;
SimpleCursorAdapter sca;
Cursor csr;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_so46330096);
spinner = (Spinner) findViewById(R.id.spinner);
editbutton = (Button) findViewById(R.id.editbutton);
spinneritem = (EditText) findViewById(R.id.spinnerinput);
dbhlpr = new SpinnerDatabase(this);
csr = dbhlpr.getAll();
sca = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
csr,
new String[]{SpinnerDatabase.KEY_NAME},
new int[]{android.R.id.text1},0);
spinner.setAdapter(sca);
editbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (spinneritem.getText().toString().length() > 0) {
dbhlpr.updateSpinner(spinner.getSelectedItemId(),spinneritem.getText().toString());
sca.swapCursor(csr = dbhlpr.getAll());
}
}
});
}
}
The Layout activity_so46330096.xml
<?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="match_parent"
android:layout_height="wrap_content"
android:text="SO463300096 Activity"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="SPINNER ENTRY"
/>
<EditText
android:id="@+id/spinnerinput"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="match_parent" />
<Button
android:id="@+id/editbutton"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="EDIT"/>
</LinearLayout>
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Spinner>
</LinearLayout>
Example usage:-
Spinner selected (note update data has already been entered):-
Peanut Butter selected and Updated data entered :-
After Clicking Edit button :-
Setting the EditText to the currently selected Spinner Item
The following can be used to set the EditText to the value of the currently selected spinner item:-
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
spinneritem.setText(csr.getString(csr.getColumnIndex(SpinnerDatabase.KEY_NAME)));
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
The could be added after setting the Adapter in the Activity.
In the aboveSO46330096Activity.java it could follow the line :-
spinner.setAdapter(sca);
来源:https://stackoverflow.com/questions/46330096/how-can-i-update-a-field-of-my-spinner-with-user-input-in-edittext