ListView 没有向我显示包含来自数据库的名称的列表。我使用 SimpleCursorAdapter

The ListView doesn't show me a list with names from database. I use SimpleCursorAdapter

我正在尝试为我的应用程序实施数据库。这是我第一次这样做。 我有一个带有列表视图的布局,我使用 SimpleCoursorAdapter 将数据从数据库传输到我的 ListView。该应用程序不显示任何内容。 ListView 是空的我不知道为什么。

这是我的 TopLevelActivity

public class TopLevelActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_top_level);

        AdapterView.OnItemClickListener itemClickListener =
                                                    new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> listView,
                                            View v,
                                            int position,
                                            long id) {
                        if(position == 0){
                            Intent intent = new Intent(TopLevelActivity.this, DrinkCategoryActivity.class);
                            startActivity(intent);
                        }
                        if(position == 1){
                            Intent intent = new Intent(TopLevelActivity.this, SnacksCategoryActivity.class);
                            startActivity(intent);
                        }

                    }
                };
        ListView listView = (ListView) findViewById(R.id.list_options);
        listView.setOnItemClickListener(itemClickListener);
    }
}

xml 来自 TopLevelActivity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".TopLevelActivity">

    <ImageView
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:src="@drawable/starbuzz_logo"
        android:contentDescription="@string/starbuzz_logo"/>

    <ListView
        android:id="@+id/list_options"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/options"/>


</LinearLayout>

我认为这里的 DrinkCategoryActivity 有一些错误

public class DrinkCategoryActivity extends Activity {
    private SQLiteDatabase db;
    private Cursor cursor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drink_category);
        ListView listDrinks = (ListView) findViewById(R.id.list_drinks);

        SQLiteOpenHelper coffeinaDatabaseHelper = new CoffeinaDatabaseHelper(this);
        try {
            db = coffeinaDatabaseHelper.getReadableDatabase();
            cursor = db.query("DRINK",
                    new String[]{"_id", "NAME"},
                    null, null, null, null, null);

            SimpleCursorAdapter listAdapter = new SimpleCursorAdapter
                    (this,
                            android.R.layout.simple_list_item_1,
                            cursor,
                            new String[]{"NAME"},
                            new int[]{android.R.id.text1},0
                            );
            listDrinks.setAdapter(listAdapter);
        } catch (SQLiteException e) {
            Toast toast = Toast.makeText(this, "Baza danych jest niedostepna",
                    Toast.LENGTH_SHORT);
            toast.show();

        }



    AdapterView.OnItemClickListener itemClickListener =
            new AdapterView.OnItemClickListener() {
                public void onItemClick(AdapterView<?> listDrinks,
                                        View itemView,
                                        int position,
                                        long id) {
                    Intent intent = new Intent(DrinkCategoryActivity.this,
                            DrinkActivity.class);
                    intent.putExtra(DrinkActivity.EXTRA_DRINKID, (int) id);
                    startActivity(intent);
                }
            };

        listDrinks.setOnItemClickListener(itemClickListener);

}

    public void onDestroy() {
        super.onDestroy();
        cursor.close();
        db.close();
    }
}

xml 来自 DrinkCategoryActivity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".DrinkCategoryActivity">

    <ListView
        android:id="@+id/list_drinks"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>





</LinearLayout>

DrinkAtivity

public class DrinkActivity extends AppCompatActivity {

    public static final String EXTRA_DRINKID = "drinkId";





    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drink);

        int drinkId = (Integer)getIntent().getExtras().get(EXTRA_DRINKID);
        
        SQLiteOpenHelper starbuzzDatabaseHelper = new CoffeinaDatabaseHelper(this);

        try{
            SQLiteDatabase db = starbuzzDatabaseHelper.getReadableDatabase();
            Cursor cursor = db.query("DRINK",
                                        new String[]{"NAME", "DESCRIPTION", "IMAGE_RESORUCE_ID"},
                    "_id = ?",
                    new String[]{Integer.toString(drinkId)},
                    null, null, null);


            if(cursor.moveToFirst()){
                String nameText = cursor.getString(0);
                String descriptionText = cursor.getString(1);
                int photoId = cursor.getInt(2);

                TextView name = (TextView)findViewById(R.id.name);
                name.setText(nameText);

                TextView description = (TextView)findViewById(R.id.description);
                description.setText(descriptionText);

                ImageView photo = (ImageView)findViewById(R.id.latte);
                photo.setImageResource(photoId);
                photo.setContentDescription(nameText);

            }
            cursor.close();
            db.close();

        }catch (SQLiteException e){
            Toast toast = Toast.makeText(this, "Bada danych jest niedostepna",
                    Toast.LENGTH_SHORT);
            toast.show();
        }


    }
}

xml 来自 DrinkActivity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".DrinkActivity">
    
    <ImageView
        android:id="@+id/latte"
        android:layout_width="190dp"
        android:layout_height="190dp"/>
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>


</LinearLayout>

我的 DataBaseHelper 和这里也可能有一些错误。 并发器没有显示任何错误。


package com.hfad.coffeina;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class CoffeinaDatabaseHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "coffeina";
    private static final int DB_VERSION = 2;

    CoffeinaDatabaseHelper(Context context){

        super(context, DB_NAME, null, DB_VERSION);
    }

    public  void onCreate(SQLiteDatabase db){
        updateMyDatabase(db, 0, DB_VERSION);

    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
            updateMyDatabase(db, oldVersion, newVersion);
    }

    private static void insertDrink(SQLiteDatabase db, String name, String description,
                                       int resourceId){
        ContentValues drinkValues = new ContentValues();
        drinkValues.put("NAME", name);
        drinkValues.put("DESCRIPTION", description);
        drinkValues.put("IMAGE_RESOURCE_ID", resourceId);
        db.insert("DRINK", null, drinkValues);

    }

    private void updateMyDatabase(SQLiteDatabase db, int oldVersion, int newVersion){
        if(oldVersion < 1){
            db.execSQL("CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
                    +"NAME TEXT, "
                    +"DESCRIPTON TEXT , "
                    +"IMAGE_RESOURCE_ID INTEGER);");
            insertDrink(db, "Latte", "Czarne espresso z gorącym mlekiem i mleczną pianką.",
                    R.drawable.latte);
            insertDrink(db, "Cappucciono", "Czarne espresso z dużą ilościa spienionego mleka",
                    R.drawable.cappuccino);
            insertDrink(db, "Espresso", "Czarna kawa ze świeżo mielonych ziaren najwyższej jakości.",
                    R.drawable.filter);
        }
        if(oldVersion < 2){
            db.execSQL("ALTER TABLE DRINK ADD COLUMN FAVORITE NUMERIC;");
        }
    }

}

来自模拟器的打印屏幕enter image description here

问题

我认为您的主要问题是在 DRINK table 中您使用 +"DESCRIPTON TEXT , " 定义了一个列名称,但您引用了 DESCRIPTION 列( tion 而不是 ton) 在其他地方包括插入 3 个初始行时。 Hidden/disguised 因为它们在 try ....catch 构造中。

请注意,将 SQLite 的东西包装在 try...catch 中通常是没有帮助的,并且会导致混淆,尤其是在测试时未检查日志的情况下。

那是日志会显示类似 :-

07-21 17:29:20.748 4340-4340/a.a.so68457788javesqlitelistview E/SQLiteLog: (1) table DRINK has no column named DESCRIPTION
07-21 17:29:20.749 4340-4340/a.a.so68457788javesqlitelistview E/SQLiteDatabase: Error inserting NAME=Latte DESCRIPTION=Czarne espresso z gorącym mlekiem i mleczną pianką. IMAGE_RESOURCE_ID=10
    android.database.sqlite.SQLiteException: table DRINK has no column named DESCRIPTION (code 1): , while compiling: INSERT INTO DRINK(NAME,DESCRIPTION,IMAGE_RESOURCE_ID) VALUES (?,?,?)
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:887)
        at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:498)
        at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
        at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
        at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
        at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1469)
        at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1341)
        at a.a.so68457788javesqlitelistview.CoffeinaDatabaseHelper.insertDrink(CoffeinaDatabaseHelper.java:32)
        at a.a.so68457788javesqlitelistview.CoffeinaDatabaseHelper.updateMyDatabase(CoffeinaDatabaseHelper.java:42)
        at a.a.so68457788javesqlitelistview.CoffeinaDatabaseHelper.onCreate(CoffeinaDatabaseHelper.java:18)

因此数据库将为空,因此 ListView 什么也不显示。

我建议始终对数据库组件使用单一定义,并且始终使用单一定义来引用组件。

建议Fix/Improvment

也许考虑使用 :-

class CoffeinaDatabaseHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "coffeina";
    private static final int DB_VERSION = 2;
    public static final String  DRINK_TABLENAME = "DRINK";
    public static final String DRINK_ID_COLUMN = BaseColumns._ID; // Android _id column name
    public static final String DRINK_NAME_COLUMN = "NAME";
    public static final String DRINK_DESCRIPTION_COLUMN = "DESCRIPTION";
    public static final String DRINK_IMAGE_RESOURCE_ID_COLUMN = "IMAGE_RESOURCE_ID";
    public static final String DRINK_FAVORITE_COLUMN = "FAVOURITE";

    CoffeinaDatabaseHelper(Context context){
        super(context, DB_NAME, null, DB_VERSION);
    }

    public  void onCreate(SQLiteDatabase db){
        updateMyDatabase(db, 0, DB_VERSION);
    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
        updateMyDatabase(db, oldVersion, newVersion);
    }

    private static void insertDrink(SQLiteDatabase db, String name, String description,
                                    int resourceId){
        ContentValues drinkValues = new ContentValues();
        drinkValues.put(DRINK_NAME_COLUMN, name);
        drinkValues.put(DRINK_DESCRIPTION_COLUMN, description);
        drinkValues.put(DRINK_IMAGE_RESOURCE_ID_COLUMN, resourceId);
        db.insert(DRINK_TABLENAME, null, drinkValues);
    }

    private void updateMyDatabase(SQLiteDatabase db, int oldVersion, int newVersion){
        if(oldVersion < 1){
            /* no need for autoincrement id's will be generated without the overheads 
                check https://sqlite.org/autoinc.html for details/why
            */
            db.execSQL("CREATE TABLE " + DRINK_TABLENAME + " (" + DRINK_ID_COLUMN + " INTEGER PRIMARY KEY, "
                    + DRINK_NAME_COLUMN + " TEXT,"
                    + DRINK_DESCRIPTION_COLUMN +" TEXT , "
                    + DRINK_IMAGE_RESOURCE_ID_COLUMN + " INTEGER);");
            insertDrink(db, "Latte", "Czarne espresso z gorącym mlekiem i mleczną pianką.",10);
            insertDrink(db, "Cappucciono", "Czarne espresso z dużą ilościa spienionego mleka", 11);
            insertDrink(db, "Espresso", "Czarna kawa ze świeżo mielonych ziaren najwyższej jakości.", 12);
        }
        if(oldVersion < 2){
            db.execSQL("ALTER TABLE DRINK ADD COLUMN " + DRINK_FAVORITE_COLUMN + " NUMERIC;");
        }
    }
}
  • 注意 用于测试的图像资源 ID 已被编造,这些将需要更改以反映您的原始代码。

然后随后使用常量在别处引用数据库组件。例如考虑以下版本的 DrinkCategoryActivity class :-

public class DrinkCategoryActivity extends AppCompatActivity {

    CoffeinaDatabaseHelper coffeinaDatabaseHelper; //<<<<< ADDED you want instance of YOUR helper not an SQLiteOpenHelper
    SQLiteDatabase db;
    Cursor cursor;
    SimpleCursorAdapter listAdapter; //<<<<< Better here, more scope
    ListView listDrinks;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drink_category);
        listDrinks = (ListView) findViewById(R.id.list_drinks);
        // SQLiteOpenHelper coffeinaDatabaseHelper = new CoffeinaDatabaseHelper(this);
        coffeinaDatabaseHelper = new CoffeinaDatabaseHelper(this);
        db = coffeinaDatabaseHelper.getWritableDatabase(); // get readable will typically get writeable anyway
        setOrRefreshListView();
    }

    private void setOrRefreshListView() {
        cursor = db.query(CoffeinaDatabaseHelper.DRINK_TABLENAME,
                new String[]{"_id", CoffeinaDatabaseHelper.DRINK_NAME_COLUMN},
                null, null, null, null, null);
        if (listAdapter == null) {
            listAdapter = new SimpleCursorAdapter(
                    this,
                    android.R.layout.simple_list_item_1, cursor,
                    new String[]{"NAME"},
                    new int[]{android.R.id.text1}, 0);
            listDrinks.setAdapter(listAdapter);
            listDrinks.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    Intent intent = new Intent(view.getContext(), DrinkActivity.class);
                    intent.putExtra(DrinkActivity.EXTRA_DRINKID, l);
                    startActivity(intent);
                }
            });
        } else {
            listAdapter.swapCursor(cursor);
        }
    }

    /* If returning to Activity (from DrinkActivity) refresh the ListView
        just in case it has changed
     */
    @Override
    protected void onResume() {
        super.onResume();
        setOrRefreshListView();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        cursor.close();
    }
}

然后使用上面的:-

额外

将上面的内容更进一步,然后是 DrinkActity 的工作(尽管没有图像)和更简洁的版本:-

public class DrinkActivity extends AppCompatActivity {

    public static final String EXTRA_DRINKID = "drinkId";
    CoffeinaDatabaseHelper DBHelper;
    SQLiteDatabase db;
    TextView name,description;
    ImageView photo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_drink);
        long drinkId = this.getIntent().getLongExtra(DrinkActivity.EXTRA_DRINKID,-1); // Should be LONG
        DBHelper = new CoffeinaDatabaseHelper(this);
        db = DBHelper.getWritableDatabase();
        name = this.findViewById(R.id.name);
        description = this.findViewById(R.id.description);
        Cursor cursor = db.query(CoffeinaDatabaseHelper.DRINK_TABLENAME,
                null,
                CoffeinaDatabaseHelper.DRINK_ID_COLUMN +" = ?",
                new String[]{String.valueOf(drinkId)}, // cope with Long
                null, null, null);
        if(cursor.moveToFirst()){
            name.setText(cursor.getString(cursor.getColumnIndex(CoffeinaDatabaseHelper.DRINK_NAME_COLUMN)));
            description.setText(cursor.getString(cursor.getColumnIndex(CoffeinaDatabaseHelper.DRINK_DESCRIPTION_COLUMN)));
            //<<<<< COMMENTED OUT FOR TESTING (as invalid resource id's have been used) >>>>>
            //photo.setImageResource(cursor.getInt(cursor.getColumnIndex(CoffeinaDatabaseHelper.DRINK_IMAGE_RESOURCE_ID_COLUMN)));
            //photo.setContentDescription(cursor.getString(cursor.getColumnIndex(CoffeinaDatabaseHelper.DRINK_NAME_COLUMN)));
        } else {
            Toast.makeText(this, "Bada danych jest niedostepna", Toast.LENGTH_SHORT).show();
        }
        cursor.close();
        //db.close(); don't close, resource expensive to open
    }
}

所以选择 Latte 会得到:-