2010-02-03 23 views
7

Estoy intentando crear un menú desplegable dinámico que se rellenará con una tabla SQLite. Tengo un objeto Cursor del que puedo extraer los datos que necesito. He sido capaz de lograr la carga de los valores en el menú desplegable con el código de abajo:Populating Spinner de la base de datos SQLite Android

Spinner s = (Spinner) findViewById(R.id.spinner); 
    ArrayAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item); 
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    s.setAdapter(adapter); 

    try{ 
     Cursor cursor = getAccounts(); 
     int accountnameIndex = cursor.getColumnIndexOrThrow(ACCOUNT_NAME); 
     if(cursor.moveToFirst()){ 
      do{ 
       adapter.add(cursor.getString(accountnameIndex)); 
      } while(cursor.moveToNext()); 
     } 
    } finally { 
     MintLink.close(); 
    } 

Mi problema es que necesito la una selección en el menú desplegable para contener también el ROWID del elemento seleccionado. Necesito poder seleccionar un artículo y tener acceso al valor de ese artículo en el back-end. Por ejemplo, piense en un menú desplegable en HTML. Cada selección desplegable tiene su propio valor oculto que se tira. Necesito ocultar este valor para permitirme saber qué ID eligen.

+0

[se puede ver aquí] (http://samir-mangroliya.blogspot.in/2012/09/android-populate-spinner-from-sqlite.html) –

Respuesta

5

Intente utilizar un SimpleCursorAdapter en lugar de copiar todos los datos a mano en un ArrayAdapter.

+2

Si bien esta es en resumen la respuesta. ¿Cuáles son los detalles al implementar SimpleCursorAdapter para trabajar con Spinner? ¿Necesito abstraer mi propio ViewBinder o puedo usar el SimpleCursorAdapter directamente con el Spinner? – crv

+0

No hay forma de responder eso en abstracto. Puedo indicarle un código de ejemplo, si es útil (aunque obtiene su cursor de ContentProvider, no de SQLite): http://github.com/commonsguy/cw-advandroid/tree/master/Contacts/Spinners/ – CommonsWare

+1

por qué recibo la advertencia obsoleta 'SimpleCursorAdapter' ahora. Lo que se debe usar ahora – DevZer0

15

Ésta es una vieja pregunta, pero la primera que encontré cuando averiguar este asunto. Aquí hay una explicación detallada con la fuente completa que puede cortar algo de trabajo de campo.

La respuesta es, de hecho, utilizar un SimpleCursorAdapter que maneja una lista de cadenas pero también tiene un manejo especial para un campo de ID coincidente que se devuelve cuando se selecciona una fila. La clave para hacer que esto funcione es conocer los dos siguientes bits de información poco claros:

1) Al crear el cursor, asegúrese de que la consulta devuelva un campo titulado "_id". Este campo no necesita mostrarse en ninguna parte, pero su valor se transmitirá cuando se seleccione un elemento de la lista.

2) Al crear un SimpleCursorAdapter, debe proporcionar los ID de diseño de TextView donde se colocará el texto de la fila. Si usa el diseño proporcionado por Android android.R.layout.simple_spinner_item, la ID de texto que necesita usar es android.R.id.text1.

Main.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
    <Spinner 
     android:id="@+id/spinner1" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_alignParentTop="true" 
     ></Spinner> 
</RelativeLayout> 

Código de actividad:

public class TesterActivity extends Activity { 
public Context mContext; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    // just for this example: 
    // create database table with an id field and a text field and add some data 
    class MyDBHelper extends SQLiteOpenHelper { 
     public MyDBHelper(Context context) { 
      super(context, "someDB", null, 2); 
     } 
     @Override 
     public void onCreate(SQLiteDatabase db) { 
      db.execSQL("CREATE TABLE someTable (someIDF INTEGER, someTextF TEXT)"); 
     } 
     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      db.execSQL("DROP TABLE IF EXISTS someTable"); 
      onCreate(db); 
      db.execSQL("INSERT INTO someTable (someIDF, someTextF) VALUES (54, 'Some text')"); 
      db.execSQL("INSERT INTO someTable (someIDF, someTextF) VALUES (99, 'Some more text')"); 
      db.execSQL("INSERT INTO someTable (someIDF, someTextF) VALUES (173, 'Even more text')"); 
     } 
    } 
    SQLiteDatabase db = new MyDBHelper(this).getWritableDatabase(); 

    // get a cursor from the database with an "_id" field 
    Cursor c = db.rawQuery("SELECT someIDF AS _id, someTextF FROM someTable", null); 

    // make an adapter from the cursor 
    String[] from = new String[] {"someTextF"}; 
    int[] to = new int[] {android.R.id.text1}; 
    SimpleCursorAdapter sca = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, c, from, to); 

    // set layout for activated adapter 
    sca.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 

    // get xml file spinner and set adapter 
    Spinner spin = (Spinner) this.findViewById(R.id.spinner1); 
    spin.setAdapter(sca); 

    // set spinner listener to display the selected item id 
    mContext = this; 
    spin.setOnItemSelectedListener(new OnItemSelectedListener() { 
     public void onItemSelected(AdapterView<?> parent, View view, int position, long id){ 
      Toast.makeText(mContext, "Selected ID=" + id, Toast.LENGTH_LONG).show(); 
     } 
     public void onNothingSelected(AdapterView<?> parent) {} 
     }); 
    } 
} 
+0

funciona en mi proyecto, pero solo brindis. cómo guardar el ID en sqlite @MindSpiker? –

3

Aquí hay otra respuesta con cargadores y cursores.

En la creación de actividad/fragmento (dicho fragmento/actividad debe aplicar LoaderManager.LoaderCallbacks<Cursor>):

final Spinner spinner = (Spinner) findViewById(R.id.spinner); 
mAdapter = new MyCursorAdapter(getActivity()); 
spinner.setAdapter(mAdapter); 
getLoaderManager().initLoader(SOME_INT_CONSTANT, null, this); 

En su actividad/fragmento:

@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    return new MyCursorLoader(getActivity(), args); 
} 

@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
    mAdapter.swapCursor(data); 
} 

@Override 
public void onLoaderReset(Loader<Cursor> loader) { 
    mAdapter.swapCursor(null); 
} 

Aquí está el adaptador de cursor:

class MyCursorAdapter extends CursorAdapter { 
    class ViewsHolder { 
     TextView text1, text2; 
    } 

    public MyCursorAdapter(Context context, Bundle args) { 
     super(context, null, false); 
     // do something with args 
    } 

    @Override 
    public View newView(Context context, Cursor cursor, ViewGroup parent) { 
     View v = LayoutInflater.from(context).inflate(R.layout.your_item_layout, parent, false); 
     ViewsHolder holder = new ViewsHolder(); 
     holder.text1 = (TextView) v.findViewById(R.id.text1); 
     holder.text2 = (TextView) v.findViewById(R.id.text2); 
     v.setTag(holder); 
     return v; 
    } 

    @Override 
    public void bindView(View view, Context context, Cursor cursor) { 
     ViewsHolder holder = (ViewsHolder) view.getTag(); 
     String text1 = cursor.getString(cursor.getColumnIndex(KEY_TEXT1)); 
     String text2 = cursor.getString(cursor.getColumnIndex(KEY_TEXT2)); 
     holder.text1.setText(text1); 
     holder.text2.setText(text2); 
    } 
} 

Aquí está el cargador de cursor:

public class MyCursorLoader extends CursorLoader { 
    private final YourSQLiteDbAdapter mHelper; 

    public MyCursorLoader(Context context) { 
     super(context); 
     mHelper = new YourSQLiteDbAdapter(context); 
     mHelper.openReadOnly(); 
    } 

    @Override 
    public Cursor loadInBackground() { 
     return mHelper.selectYourDataAsACursor(); 
    } 

    @Override 
    protected void onStopLoading() { 
     super.onStopLoading(); 
     mHelper.close(); 
    } 
} 

El uso de este que se obtiene:

  • ningún uso de API que dejarán
  • uso de la API del cargador
  • personalizados adaptador/layouts
  • vista reciclaje
  • nivel API 4 compatible con versiones anteriores (a través de soporte lib)
  • datos de subproceso cargando datos
Cuestiones relacionadas