SQLite查询不会在运行时更新XML布局

时间:2018-01-04 19:06:32

标签: java android sqlite android-sqlite

我试图创建一个基本的食物日志,人们可以在editTexts中输入食物名称和卡路里:

Layout Screenshot

onClick方法应该接受他们的输入并添加到数据库,然后运行查询以检索食物列表并将其添加回布局,以及获得总卡路里。

在主要活动中:

// Add a food to the database
public void onClickAdd(View view) {
    // Get the food stats from the layout
    String foodName = txtFood.getText().toString();
    String calString = txtCalories.getText().toString();
    int calories = Integer.parseInt(calString);

    Food food = new Food(foodName, calories);
    // Add the new food (the name and the calories)
    foodDBHandler.addProduct(food);

    // Setting the new values in the textviews
    printDatabase();
    getTotalCalories();
}

public void printDatabase(){
    String dbString = foodDBHandler.databaseToString();
    txtFoodLog.setText(dbString);
    txtFood.setText("");
}

//Get the total calories
public void getTotalCalories() {
    int dbString = foodDBHandler.sumCalories();
    txtTotalCals.setText("Total Cals: " + dbString);
    txtCalories.setText("");
}

FoodDBHandler类运行printDatabase()和getTotalCalories()使用的查询:

// Gets a list of all the foods
public String databaseToString(){
    String dbString = "";
    SQLiteDatabase db = getWritableDatabase();
    String query = "SELECT * FROM " + TABLE_FOOD + " WHERE 1";

    //Cursor points to a location in your results
    Cursor recordSet = db.rawQuery(query, null);
    //Move to the first row in your results
    recordSet.moveToFirst();

    //Position after the last row means the end of the results
    while (!recordSet.isAfterLast()) {
        // null could happen if we used our empty constructor
        if (recordSet.getString(recordSet.getColumnIndex("foodname")) != null) {
            dbString += recordSet.getString(recordSet.getColumnIndex("foodname"));
            dbString += "\n";
        }
        recordSet.moveToNext();
    }
    db.close();
    return dbString;
}

public int sumCalories(){
    /*
    This method goes through the entire db, then checks if there are empty values in the food column
    If the column is not null, then it takes the calorie value of the food and adds it on to the dbString value (which is an integer despite the name)
    */

    int dbString = 0;
    SQLiteDatabase db = getWritableDatabase();
    String query = "SELECT * FROM " + TABLE_FOOD + " WHERE 1";

    //Cursor points to a location in the results
    Cursor recordSet = db.rawQuery(query, null);
    //Move to the first row in your results
    recordSet.moveToFirst();

    //Position after the last row means the end of the results
    while (!recordSet.isAfterLast()) {
        // null could happen if we used our empty constructor
        if (recordSet.getString(recordSet.getColumnIndex("foodname")) != null) {
            dbString += recordSet.getInt(recordSet.getColumnIndex("calories"));
        }
        recordSet.moveToNext();
    }
    db.close();
    return dbString;
}

问题是,当我点击onClickAdd按钮时,文本会从布局中消失,而不会从表中发回信息。

这是我更新内容或数据库本身的方式吗?

2 个答案:

答案 0 :(得分:0)

我相信查询中存在一些问题

 String query = "SELECT * FROM " + TABLE_FOOD + " WHERE 1";

理想情况下,您必须在查询中提供column_name

String query = "SELECT * FROM " + TABLE_FOOD + " WHERE QUANTITY = 1";

答案 1 :(得分:0)

由于您的问题的原因可能很多,这里有一个有效的应用程序示例。但是,它不使用看起来像TextView的东西来显示食物列表,而是使用ListView。

虽然不是一个具体的答案,但目的是提供一个可以突出问题并从而回答问题的工作实例。

MainActivity.java: -

public class MainActivity extends AppCompatActivity {

    EditText txtFood, txtCalories;
    Button mAddFood, mDeleteFood, mBack;
    ListView mFoodListListView;  //<<<< ListView rather than text with new lines
    TextView txtTotalCals;
    SimpleCursorAdapter mSCA;   // <<<< Cursor Adapter for the ListView
    Cursor mFoodListCursor;     // <<<< Cursor to populate the ListView

    FoodDBHandler fh;           // <<<< DB Helper (CAN't BE INSTANIATED YET)

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

        // Get Views form thier ID's
        txtFood = (EditText) this.findViewById(R.id.et_food);
        txtCalories = (EditText) this.findViewById(R.id.et_calories);
        mAddFood = (Button) this.findViewById(R.id.btn_addfood);
        mDeleteFood = (Button) this.findViewById(R.id.btn_dltfood);
        mBack = (Button) this.findViewById(R.id.btn_back);
        mFoodListListView = (ListView) this.findViewById(R.id.foodlist);
        txtTotalCals = (TextView) this.findViewById(R.id.caloriecount);

        // Instantiate the FoodHandler instance
        fh = new FoodDBHandler(this);

        // Load the Listview with data if any.
        mFoodListCursor = fh.getAllFoods();
        mSCA = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_2,
                mFoodListCursor,
                new String[]{ FoodDBHandler.COL_FOOD_NAME, FoodDBHandler.COL_CALORIES},
                new int[]{android.R.id.text1, android.R.id.text2},
                0);
        mFoodListListView.setAdapter(mSCA);
        txtTotalCals.setText(fh.getTotalCalories());

        //Set the Button click listeners
        setAddFoodButtonListener();
        setDeleteFoodButtonListener();
        setBackButtonListener();
    }

    private void setBackButtonListener() {
        mBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("BACKBUTTONCLICK","The back button was clicked.");
                // finish(); commented out as this main activity
            }
        });
    }

    private void setAddFoodButtonListener() {
        mAddFood.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (txtFood.length() < 1 || txtCalories.length() < 1) {
                    Toast.makeText(
                            getApplicationContext(),
                            "Unable to Add - Blank Value(s).",
                            Toast.LENGTH_LONG
                    ).show();
                    return;
                }
                fh.addFood(
                        txtFood.getText().toString(),
                        Integer.valueOf(txtCalories.getText().toString()));
                refreshListView();
            }
        });
    }

    private void setDeleteFoodButtonListener() {
        mDeleteFood.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (txtFood.length() < 1 || txtCalories.length() < 1) {
                    Toast.makeText(
                            getApplicationContext(),
                            "Unable to Delete - Blank Value(s).",
                            Toast.LENGTH_LONG
                    ).show();
                    return;
                }
                String foodname = txtFood.getText().toString();
                long caloroies = Long.valueOf(txtCalories.getText().toString());
                long id;
                if ((id =fh.getIdFromNameAndCalories(foodname,caloroies)) > 0) {
                    if (fh.deleteFood(id)) {
                        Toast.makeText(
                                getApplicationContext(),
                                "Deleted.",
                                Toast.LENGTH_LONG
                        ).show();
                        refreshListView();
                    } else {
                        Toast.makeText(
                                getApplicationContext(),
                                "Oooops not Deleted????",
                                Toast.LENGTH_LONG
                        ).show();
                    }
                } else {
                    Toast.makeText(
                            getApplicationContext(),
                            "Unable to Delete - Not Found.",
                            Toast.LENGTH_LONG
                    ).show();
                }
            }
        });
    }

    private void refreshListView() {
        mFoodListCursor = fh.getAllFoods();
        mSCA.swapCursor(mFoodListCursor);
        txtTotalCals.setText(fh.getTotalCalories());
    }
}

注释

  • 由于这是主要活动/初始活动后退按钮已被禁用。通常,finish()方法将由返回到调用活动的调用活动调用。您通常不会在主活动中执行此操作,因为没有调用活动。
  • 如果有多个相同的组合,则删除食物不会删除食物/卡路里组合(添加允许以书面形式)。

FoodHandler.java: -

public class FoodDBHandler extends SQLiteOpenHelper {

    public static final String DBNAME = "foods";
    public static final int DBVERSION = 1;
    public static final String TABLE_FOOD = "food";
    public static final String COL_FOOD_ID = BaseColumns._ID;
    public static final String COL_FOOD_NAME = "foodname";
    public static final String COL_CALORIES = "calories";

    Context mContext;
    SQLiteDatabase mDB;

    FoodDBHandler(Context context) {
        super(context, DBNAME, null, DBVERSION);
        mContext = context;
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String crttblsql = "CREATE TABLE IF NOT EXISTS " +
                TABLE_FOOD +
                " (" +
                COL_FOOD_ID + " INTEGER PRIMARY KEY, " +
                COL_FOOD_NAME + " TEXT, " +
                COL_CALORIES + " INTEGER " +
                ")";
        db.execSQL(crttblsql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    // Gets a list of all the foods <<<< NO LONGER USED
    public String databaseToString() {
        String dbString = "";
        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM " + TABLE_FOOD + " WHERE 1";

        //Cursor points to a location in your results
        Cursor recordSet = db.rawQuery(query, null);
        //Move to the first row in your results
        recordSet.moveToFirst();

        //Position after the last row means the end of the results
        while (!recordSet.isAfterLast()) {
            // null could happen if we used our empty constructor
            if (recordSet.getString(recordSet.getColumnIndex("foodname")) != null) {
                dbString += recordSet.getString(recordSet.getColumnIndex("foodname"));
                dbString += "\n";
            }
            recordSet.moveToNext();
        }
        //NOTE! no cursor.close() SHOULD ALWAYS CLOSE A CURSOR WHEN DONE WITH IT
        db.close();
        return dbString;
    }

    // Example of how databaseToString could be written <<< NOT USED
    public String altDatabaseToString() {
        StringBuilder dbString = new StringBuilder();
        Cursor recordset = mDB.query(TABLE_FOOD,null,null,null,null,null,null);
        int columncount = recordset.getCount();
        while (recordset.moveToNext()) {
            dbString.append(recordset.getString(recordset.getColumnIndex(COL_FOOD_NAME)));
            if (recordset.getPosition() < (columncount - 1)) {
                dbString.append("\n");
            }
        }
        recordset.close();
        return dbString.toString();
    }

    // <<<< Equivalent to addProduct
    public boolean addFood(String food, int calories) {
        ContentValues cv = new ContentValues();
        cv.put(COL_FOOD_NAME,food);
        cv.put(COL_CALORIES,calories);
        return mDB.insert(TABLE_FOOD,null,cv) > 0;
    }

    // <<<< deleteFood according to id column
    public boolean deleteFood(long id) {
         return mDB.delete(TABLE_FOOD,COL_FOOD_ID + "=?",new String[]{String.valueOf(id)}) > 0;
    }

    // <<<< get the id column according to name and calorie columns
    // NOTE! will only allow return of id if there is no ambiguity
    // i.e. name/calorie combination must be unique
    public long getIdFromNameAndCalories(String foodname, long calroies) {
        long rv = -1;
        Cursor csr = mDB.query(TABLE_FOOD,
                null,
                COL_FOOD_NAME +
                        "=? AND "+
                        COL_CALORIES +
                        "=?",
                new String[]{foodname,String.valueOf(calroies)},null,null,null);
        // Ambiguous as extracted multiple rows i.e. which one to delete????
        if (csr.getCount() > 1) {
            return rv;
        }
        if (csr.moveToNext()) {
            rv = csr.getLong(csr.getColumnIndex(COL_FOOD_ID));
        }
        csr.close();
        return rv;
    }

    // <<<< Uses SQL features to get the sum of the calories
    public String getTotalCalories() {
        String rvcolumn = "caloriecount";
        String rv = "0";
        Cursor csr =mDB.query(TABLE_FOOD,
                new String[]{"sum(" + COL_CALORIES +") AS " + rvcolumn},
                null,null,
                null,
                null,
                null
        );
        if (csr.moveToFirst()) {
            rv = Integer.toString(csr.getInt(csr.getColumnIndex(rvcolumn)));
        }
        csr.close();
        return rv;
    }

    // <<<< Simply get all rows from the database
    public Cursor getAllFoods() {
        return mDB.query(TABLE_FOOD,
                null,
                null,
                null,
                null,
                null,
                null
        );
    }
}

注释

  • 有一些冗余方法,注释表明如此。
  • 当然,表格的结构是基于假设的。

activity_main.xml: -

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

    <EditText
        android:id="@+id/et_food"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="10"
        android:hint="Your Food"
        />
    <EditText
        android:id="@+id/et_calories"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_weight="10"
        android:inputType="number"
        android:hint="Calories"/>
    <TextView
        android:id="@+id/tv_record"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <ListView
        android:id="@+id/foodlist"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="50">
    </ListView>
    <TextView
        android:id="@+id/caloriecount"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:orientation="horizontal"
        android:id="@+id/buttons"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="10">
        <Button
            android:layout_marginLeft="10dp"
            android:id="@+id/btn_addfood"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Add"
            />
        <Button
            android:layout_marginRight="10dp"
            android:id="@+id/btn_dltfood"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Delete"
            />
    </LinearLayout>
    <Button
        android:id="@+id/btn_back"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="10"
        android:layout_gravity="center_horizontal"
        />
</LinearLayout>

屏幕截图示例: -

  • 初始(首次运行): -

enter image description here

  • 新增1种食物: -
    • 填充ListView。
    • 调整卡路里计数。
    • 删除将删除并恢复到之前的屏幕。

enter image description here

  • 添加了多种食物: -

enter image description here