我无法更新数据库中某个项目的数据

问题描述 投票:0回答:1

我是android开发新手,请帮忙。我有一个 RecyclerView – 它有一个相对的项目列表,每个项目都有机会将其添加到收藏夹。

单击 ImageButton 时,会调用 updateAddToFavourite 方法,该方法应该更新数据库中记录上的数据(将列中的值从 0 更改为 1),但是当我启动应用程序并单击收藏夹按钮时,我收到错误:

致命异常:主要 进程:com.example.foodmap,PID:16170 kotlin.UninitializedPropertyAccessException:lateinit 属性数据库尚未初始化

我做错了什么?

MainActivity.kt

package com.example.foodmap

import android.content.Intent
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.RecyclerView
import com.example.foodmap.DatabaseHelper
import com.example.foodmap.DatabaseHelper.columnProducts_id
import com.example.foodmap.DatabaseHelper.columnSafetyIndicator
import com.example.foodmap.DatabaseHelper.tableProducts
import com.example.foodmap.databinding.ActivityMainBinding
import com.mikepenz.materialdrawer.AccountHeader
import com.mikepenz.materialdrawer.AccountHeaderBuilder
import com.mikepenz.materialdrawer.Drawer
import com.mikepenz.materialdrawer.DrawerBuilder
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem

class MainActivity : AppCompatActivity(), OnItemClickListener {
    private lateinit var binding: ActivityMainBinding
    private lateinit var databaseHelper: DatabaseHelper
    lateinit var db: SQLiteDatabase
    private lateinit var productCursor: Cursor
    private lateinit var fodmapCursor: Cursor
    private lateinit var productAdapter: ProductAdapter
    private lateinit var recyclerView: RecyclerView
    private lateinit var mDrawer: Drawer
    private lateinit var mHeader: AccountHeader
    private lateinit var mToolbar: Toolbar
    private val TAG = "MainActivity" // костыль чтобы вызвать метод из MainActivity

    private fun initial() {
        recyclerView = binding.rvProducts
        productAdapter = ProductAdapter(myProducts(), this)
        recyclerView.adapter = productAdapter
        mToolbar = binding.mainToolbar
    }

    private fun initFunc() {
        setSupportActionBar(mToolbar)
        createHeader()
        createDrawer()
    }

    private fun createDrawer() {
        mDrawer =
            DrawerBuilder()
                .withActivity(this)
                .withToolbar(mToolbar)
                .withActionBarDrawerToggle(true)
                .withSelectedItem(-1)
                .withAccountHeader(mHeader)
                .addDrawerItems(
                    PrimaryDrawerItem().withIdentifier(1)
                        .withIconTintingEnabled(true)
                        .withName("Профиль пользователя")
                        .withSelectable(false),
                    PrimaryDrawerItem().withIdentifier(2)
                        .withIconTintingEnabled(true)
                        .withName("Мой дневник")
                        .withSelectable(false),
                    PrimaryDrawerItem().withIdentifier(3)
                        .withIconTintingEnabled(true)
                        .withName("Мои продукты")
                        .withSelectable(false),
                    PrimaryDrawerItem().withIdentifier(4)
                        .withIconTintingEnabled(true)
                        .withName("Мои рецепты")
                        .withSelectable(false),
                    PrimaryDrawerItem().withIdentifier(5)
                        .withIconTintingEnabled(true)
                        .withName("Выход")
                        .withSelectable(false)
                ).withOnDrawerItemClickListener(object : Drawer.OnDrawerItemClickListener {
                    override fun onItemClick(
                        view: View?,
                        position: Int,
                        drawerItem: IDrawerItem<*>
                    ): Boolean {
                        val newIntent = Intent(this@MainActivity, SelectedProducts::class.java)

                        when (position) {
                            3 -> startActivity(newIntent)
                        }
                        return false
                    }
                }).build()
    }

    private fun createHeader() {
        mHeader = AccountHeaderBuilder()
            .withActivity(this)
            .withHeaderBackground(R.drawable.header)
            .addProfiles(
                ProfileDrawerItem()
                    .withName("Денис Белозёров")
                    .withIcon(R.drawable._avatar180)
                    .withEmail("[email protected]")
            )
            .build()
    }

    private fun myProducts(): ArrayList<ProductModel> {
        val productList = ArrayList<ProductModel>()
        val count: Int = productCursor.count

        var i = 0
        while (i < count) {
            var colorSafety = getColor(R.color.green) // храним цвет каждого продукта

            productCursor.moveToPosition(i)
            val nameProduct: String =
                productCursor.getString(productCursor.getColumnIndexOrThrow(DatabaseHelper.columnProductsName))
            val categoryProduct: String =
                productCursor.getString(productCursor.getColumnIndexOrThrow(DatabaseHelper.columnCategoryName))
            val safetyIndicator: String =
                productCursor.getString(productCursor.getColumnIndexOrThrow(DatabaseHelper.columnSafetyIndicator))

            when (safetyIndicator) {
                "Безопасен" -> colorSafety = getColor(R.color.green)
                "Небезопасен" -> colorSafety = getColor(R.color.red)
                "Умеренно безопасен" -> colorSafety = getColor(R.color.yellow)
            }

            productList.add(ProductModel(nameProduct, categoryProduct, colorSafety))
            i++
        }
        return productList
    }

    private fun createAlertDialog(
        title: String,
        olygos: String,
        fructose: String,
        polyols: String,
        lactose: String,
        weight: String
    ) {
        val productDialogView =
            LayoutInflater.from(this).inflate(R.layout.custom_alert_dialog_info_products_1, null)
        val builder = AlertDialog.Builder(this).setView(productDialogView).setTitle(title)

        val textViewWeight: TextView = productDialogView.findViewById(R.id.Product_weight_1_1_1)
        val textViewOlygos: TextView = productDialogView.findViewById(R.id.Olygos_1_1_2)
        val textViewFructose: TextView = productDialogView.findViewById(R.id.Fructose_1_1_3)
        val textViewPolyols: TextView = productDialogView.findViewById(R.id.Polyols_1_1_4)
        val textViewLactose: TextView = productDialogView.findViewById(R.id.Lactose_1_1_5)

        textViewWeight.setText(weight + " гр")
        textViewOlygos.setText(olygos)
        textViewFructose.setText(fructose)
        textViewPolyols.setText(polyols)
        textViewLactose.setText(lactose)

        builder.setPositiveButton("OK") { dialog, which ->
        }
        builder.show()
    }

    override fun onItemClicked(product: ProductModel) {
        val queryFodmap =
            "SELECT Продукты._id, Продукты.[Название продукта], Продукты.[Наличие глютена], FODMAP.[Единицы измерения гр], FODMAP.[Наличие Olygos (олигосахариды)], FODMAP.[Наличие Fructose (фруктоза)], FODMAP.[Наличие Polyols (полиолы)], FODMAP.[Наличие Lactose (лактоза)] FROM Продукты INNER JOIN FODMAP ON Продукты.[Название продукта] = FODMAP.[Название продукта] WHERE Продукты.[Название продукта] = \"${product.product}\""
        fodmapCursor = db.rawQuery(queryFodmap, null)
        fodmapCursor.moveToFirst()
        val itemOlygos =
            fodmapCursor.getString(fodmapCursor.getColumnIndexOrThrow(DatabaseHelper.columnFodmapOlygos)) // извлекаем характеристики продукта и передаем в AlertDialog
        val itemFructose =
            fodmapCursor.getString(fodmapCursor.getColumnIndexOrThrow(DatabaseHelper.columnFodmapFructose))
        val itemPolyols =
            fodmapCursor.getString(fodmapCursor.getColumnIndexOrThrow(DatabaseHelper.columnFodmapPolyols))
        val itemLactose =
            fodmapCursor.getString(fodmapCursor.getColumnIndexOrThrow(DatabaseHelper.columnFodmapLactose))
        val itemWeight =
            fodmapCursor.getString(fodmapCursor.getColumnIndexOrThrow(DatabaseHelper.columnFodmapUnit))
        createAlertDialog(
            "${product.product}",
            itemOlygos,
            itemFructose,
            itemPolyols,
            itemLactose,
            itemWeight
        )
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        databaseHelper = DatabaseHelper(applicationContext)
        databaseHelper.create_db()
    }

    override fun onResume() {
        super.onResume()
        db = databaseHelper.open()

        val queryProducts =
            "SELECT * FROM " + DatabaseHelper.tableProducts + " INNER JOIN " + DatabaseHelper.tableCategory + " ON " + "Продукты.[Категория продукта] = Категория.[Код категории]"
        val queryFodmap =
            "SELECT Продукты._id, Продукты.[Название продукта], Продукты.[Наличие глютена], FODMAP.[Единицы измерения гр], FODMAP.[Наличие Olygos (олигосахариды)], FODMAP.[Наличие Fructose (фруктоза)], FODMAP.[Наличие Polyols (полиолы)], FODMAP.[Наличие Lactose (лактоза)]\n" +
                    "FROM Продукты INNER JOIN FODMAP ON Продукты.[Название продукта] = FODMAP.[Название продукта]"

        productCursor = db.rawQuery(queryProducts, null)
        fodmapCursor = db.rawQuery(queryFodmap, null)

        initial()
        initFunc()
    }

    override fun onDestroy() {
        super.onDestroy()
        db.close()
        productCursor.close()
    }

    companion object {
        val instance = MainActivity()
    }

    fun updateAddToFavourite(position: Int) {
        db.execSQL("UPDATE ${DatabaseHelper.tableProducts} SET ${DatabaseHelper.columnSafetyIndicator} = 1 WHERE ${DatabaseHelper.columnProducts_id} == $position")
    }
}

DatabaseHelper.java

package com.example.foodmap;

import android.database.SQLException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.content.Context;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class DatabaseHelper extends SQLiteOpenHelper {
    private static String DB_PATH;
    private static String DB_NAME = "fodmap.db";
    private static final int SCHEMA = 1;
    static final String tableProducts = "Продукты";
    static final String columnProducts_id = "_id";
    static final String columnProductsName = "Название продукта";
    static final String columnProductsCode = "Код продукта";
    static final String columnProductsCategory = "Категория продукта";
    static final String columnProductsGluten = "Наличие глютена";
    static final String columnProductsProtein = "Содержание белков (на 100 гр)";
    static final String columnProductsFats = "Содержание жиров (на 100 гр)";
    static final String columnProductsCarb = "Содержание углеводов (на 100 гр)";
    static final String columnSafetyIndicator = "Индикатор безопасности";

    static final String tableCategory = "Категория";
    static final String columnCategoryCode = "Код категории";
    static final String columnCategoryName = "Название категории";

    static final String tableFODMAP = "FODMAP";
    static final String columnFodmapProducts = "Название продукта";
    static final String columnFodmapUnit = "Единицы измерения гр";
    static final String columnFodmapOlygos = "Наличие Olygos (олигосахариды)";
    static final String columnFodmapFructose = "Наличие Fructose (фруктоза)";
    static final String columnFodmapPolyols = "Наличие Polyols (полиолы)";
    static final String columnFodmapLactose = "Наличие Lactose (лактоза)";

    private Context myContext;

    DatabaseHelper(Context context) {
        super(context, DB_NAME, null, SCHEMA);
        this.myContext = context;
        DB_PATH = context.getFilesDir().getPath() + DB_NAME;
    }

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

    void create_db(){

        File file = new File(DB_PATH);
        if (!file.exists()) {
            //получаем локальную бд как поток
            try(InputStream myInput = myContext.getAssets().open(DB_NAME);
                // Открываем пустую бд
                OutputStream myOutput = new FileOutputStream(DB_PATH)) {

                // побайтово копируем данные
                byte[] buffer = new byte[1024];
                int length;
                while ((length = myInput.read(buffer)) > 0) {
                    myOutput.write(buffer, 0, length);
                }
                myOutput.flush();
            }
            catch(IOException ex){
                Log.d("DatabaseHelper", ex.getMessage());
            }
        }
    }
    public SQLiteDatabase open()throws SQLException {
        return SQLiteDatabase.openDatabase(DB_PATH, null, SQLiteDatabase.OPEN_READWRITE);
    }
}

产品适配器.kt

package com.example.foodmap
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView
import com.example.foodmap.databinding.ItemProductsLayoutBinding

class MyHolder(val binding: ItemProductsLayoutBinding) : RecyclerView.ViewHolder(binding.root) {
    val name_product = binding.nameProduct
    val name_category = binding.categoryProduct
    val safety_indicator: ImageView = binding.safetyIndicator
    val add_to_favorite: ImageButton = binding.addToFavorite
    var buttonOn: Boolean = false

    fun bind(product: ProductModel, clickListener: OnItemClickListener) {
        name_product.text = product.product
        name_category.text = product.category
        safety_indicator.setColorFilter(product.safetyIndicator)

        itemView.setOnClickListener {
            clickListener.onItemClicked(product)
        }
    }
}

class ProductAdapter(
    private var products: ArrayList<ProductModel>,
    val itemClickListener: OnItemClickListener
) : RecyclerView.Adapter<MyHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_products_layout, parent, false)
        return MyHolder(ItemProductsLayoutBinding.inflate(LayoutInflater.from(parent.context), parent,false))
    }

    override fun onBindViewHolder(myHolder: MyHolder, position: Int) {
        val currentPosition = products.get(position)
        myHolder.bind(currentPosition, itemClickListener)

        myHolder.binding.addToFavorite.setOnClickListener {
            if (!myHolder.buttonOn) {
                myHolder.buttonOn = true
                myHolder.add_to_favorite.setImageResource(R.drawable.baseline_favorite_24)
                val getMainActivity = MainActivity.instance
                getMainActivity.updateAddToFavourite(position)

            } else {
                myHolder.buttonOn = false
                myHolder.add_to_favorite.setImageResource(R.drawable.baseline_favorite_border_24)
            }
        }
    }

    override fun getItemCount(): Int {
        return products.size
    }

    @SuppressLint("NotifyDataSetChanged")
    fun setList(list: ArrayList<ProductModel>) {
        products = list
        notifyDataSetChanged()
    }
}

interface OnItemClickListener {
    fun onItemClicked(product: ProductModel)
}

item_products_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="2dp" >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/icon_product"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/no_image"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_margin="2dp" >
            <TextView
                android:id="@+id/name_product"
                android:layout_width="match_parent"
                android:layout_height="25dp"
                android:layout_marginLeft="55dp"
                android:layout_marginRight="105dp"
                android:layout_toRightOf="@id/icon_product"
                android:gravity="center_vertical"
                android:textColor="@color/black"
                android:textSize="16sp"
                android:text="Product"
                android:textStyle="bold" />
            <TextView
                android:id="@+id/category_product"
                android:layout_width="match_parent"
                android:layout_height="25dp"
                android:layout_marginLeft="55dp"
                android:layout_marginRight="105dp"
                android:layout_toRightOf="@id/icon_product"
                android:gravity="center_vertical"
                android:textColor="@color/black"
                android:textSize="14sp"
                android:text="Category"
                android:textStyle="italic" />
        </LinearLayout>

        <de.hdodenhof.circleimageview.CircleImageView
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/safety_indicator"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_toLeftOf="@+id/add_to_favorite"
            android:layout_centerVertical="true"
            android:src="@color/red"
            app:civ_border_width="1dp"
            app:civ_border_color="#FF000000"/>

        <ImageButton
            android:id="@+id/add_to_favorite"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerVertical="true"
            android:src="@drawable/baseline_favorite_border_24"
            android:background="@null"
            android:layout_alignParentRight="true" />
    </RelativeLayout>
</androidx.cardview.widget.CardView>

我不明白为什么初始化数据库会出错,所以我尝试在OnStart方法中添加初始化,但这并没有导致变化。

android kotlin android-recyclerview android-sqlite
1个回答
0
投票

错误消息“kotlin.UninitializedPropertyAccessException:lateinit property db尚未初始化”表示您在初始化之前尝试使用

db
属性。要解决此问题,您需要确保
db
属性在使用之前已正确初始化。

在您的

MainActivity
中,您应该通过在
db
databaseHelper.open()
方法中调用
onCreate
方法来初始化
onResume
属性。这可确保在执行任何数据库操作之前数据库已打开并可供使用。

此外,请确保调整代码中可能依赖于初始化数据库才能正常工作的其他部分。

有关 Android 开发和使用数据库的进一步指导,您可以参考有关 SQLite 数据库的 Android 官方文档: Android SQLite 数据库文档

© www.soinside.com 2019 - 2024. All rights reserved.