GDPU Android移动应用 数据存储

news2024/11/29 8:57:25

又是学到了数据持久化。

登录界面

题外话:有无动画大佬带带呀,前端移动端可免( •̀ .̫ •́ ),合作可私信哦。

1.用户登陆和“记住我”功能

该内容拥有两个Activity活动视图:

(1)LoginActivity(LoginActivity.kt、activity_login.xml):登陆和注册Activity,具备用户登录和记住帐户密码的功能;

(2)MainActivity(MainActivity.kt、activity_main.xml):登陆成功后显示的主页面,显示“登陆成功!”(TextView)。

在登陆活动LoginActivity中,可基于“实验4界面设计1”的登陆Activity进行开发设计,包含的控件有:

(1)“用户名”和“密码”的输入框(EditText)和对应的文本说明(TextView),

(2)“注册”按钮(Button)

(3)“登陆”按钮(Button)

(4)“记住我”勾选框(CheckBox)

实现以下功能(需求):

(1)普通登陆成功:用户可以输入用户名和密码,然后点击“登陆”,如果用户名和密码正确,即可登录,跳转到MainActivity中。

(2)普通登陆失败:用户可以输入用户名和密码,然后点击“登陆”,如果用户名或密码不正确,弹出警告对话窗(参考4.2.6节),提醒用户重新输入。

(3)“记住我“登陆成功:用户可以输入用户名和密码,勾选“记住我”勾选框后,然后点击“登陆”,如果用户名和密码正确,即可登录,此时会跳转到MainActivity。同时,根据勾选“记住我”作为条件判断,记住当前正确验证的用户名和密码信息。那么,在下一次打开应用的LoginActivity时,会自动填写用户名和密码信息。

(4)“记住我“登陆失败:用户可以输入用户名和密码,勾选“记住我”勾选框后,然后点击“登陆”,如果用户名或密码不正确,弹出警告对话窗,提醒用户重新输入。同时,不会根据“记住我”勾选框进行用户名和密码信息的保存。

(5)用户名和密码信息保存:通过SharedPreferences方式进行保存,文件名命名为“remember”。

(6)用户注册:用户可在“用户名”和“密码”的输入框进行输入,点击“注册”即可注册帐户。注册时,需要检查用户名是否重复,如果重复,则弹出警告对话框提醒;如果不重复,则弹出Toast显示“注册成功”提醒注册成功。

(7)用户注册信息保存:成功注册的帐户,以文件存储方式,将文件名命名为“accounts”来保存用户名和密码信息,用户名和密码信息按以下格式进行保存:

用户名1,密码1

用户名2,密码2

用户名3,密码3

解释:用户名和密码以英文逗号隔开,每一行保存一个帐户信息。

这道题的主活动就是一行文本很简单,所以主活动改为下一题的,即可以先写一个登录界面,然后直接进入主界面进行添加图书。

LoginActivity.kt

package com.example.t8

import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.CheckBox
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AlertDialog

class LoginActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)  // 修正了布局文件名称

        val userNameEditText: EditText = findViewById(R.id.userName)
        val passWordEditText: EditText = findViewById(R.id.passWord)
        val rememberMeCheckBox: CheckBox = findViewById(R.id.rememberMe)

        // 获取 SharedPreferences
        val prefs = getPreferences(Context.MODE_PRIVATE)
        val isRememberMe = prefs.getBoolean("remember_me", false)
        // 如果记住密码,设置已保存的用户名和密码
        if (isRememberMe) {
            val username = prefs.getString("username", "") ?: ""
            val password = prefs.getString("password", "") ?: ""
            userNameEditText.setText(username)
            passWordEditText.setText(password)
            rememberMeCheckBox.isChecked = true
        }
        // 注册按钮点击事件
        val registerButton: Button = findViewById(R.id.register)
        registerButton.setOnClickListener {
            val username = userNameEditText.text.toString()
            val password = passWordEditText.text.toString()

            if (prefs.contains(username)) {
                AlertDialog.Builder(this)
                    .setTitle("注册失败")
                    .setMessage("用户名已存在,请重新输入!")
                    .setPositiveButton("确定", null)
                    .show()
            } else if (username.isEmpty()) {
                Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show()
            } else if (password.isEmpty()) {
                Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show()
            } else {
                val editor = prefs.edit()
                editor.putString(username, password)
                editor.apply()
                Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT).show()
                userNameEditText.text.clear()
                passWordEditText.text.clear()
            }
        }

        // 登录按钮点击事件
        val loginButton: Button = findViewById(R.id.login)
        loginButton.setOnClickListener {
            val username = userNameEditText.text.toString()
            val password = passWordEditText.text.toString()

            if (prefs.getString(username, "") == password) {
                val editor = prefs.edit()
                if (rememberMeCheckBox.isChecked) {
                    editor.putBoolean("remember_me", true)
                    editor.putString("username", username)
                    editor.putString("password", password)
                } else {
                    editor.clear()
                }
                editor.apply()

                // 登录成功,跳转到 MainActivity
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
                finish()
            } else if (username.isEmpty()) {
                Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show()
            } else if (password.isEmpty()) {
                Toast.makeText(this, "密码不能为空", Toast.LENGTH_SHORT).show()
            } else {
                AlertDialog.Builder(this)
                    .setTitle("登录失败")
                    .setMessage("用户名或密码错误")
                    .setPositiveButton("确定", null)
                    .show()
            }
        }
    }
}

activity_login.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- First LinearLayout (for username and password input) -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="horizontal"
        android:gravity="bottom">

        <TextView
            android:id="@+id/textName"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="@string/username"
            android:textSize="23sp"
            android:layout_gravity="center"
            android:layout_marginStart="16dp" />

        <EditText
            android:id="@+id/userName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="@string/enter_username"
            android:textSize="23sp"
            android:layout_gravity="center_vertical"
            android:layout_marginEnd="16dp" />

    </LinearLayout>

    <!-- Second LinearLayout (for password input) -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="horizontal"
        android:gravity="bottom">

        <TextView
            android:id="@+id/textPwd"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="@string/password"
            android:textSize="23sp"
            android:gravity="center"
            android:layout_marginStart="16dp" />

        <EditText
            android:id="@+id/passWord"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="请输入密码"
            android:textSize="23sp"
            android:gravity="center_vertical"
            android:layout_marginEnd="16dp"
            android:inputType="textPassword" />

    </LinearLayout>

    <!-- Third LinearLayout (for remember me checkbox) -->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <CheckBox
            android:id="@+id/rememberMe"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="17dp"
            android:layout_marginStart="25dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"
            android:layout_marginTop="20dp"
            android:text="@string/remember_me" />

    </LinearLayout>

    <!-- Fourth LinearLayout (for login and register buttons) -->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp"
        android:layout_gravity="center">

        <Button
            android:id="@+id/login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/login"
            android:textSize="24sp"
            android:layout_margin="10dp" />

        <Button
            android:id="@+id/register"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/register"
            android:textSize="24sp"
            android:layout_margin="10dp" />

    </LinearLayout>

</LinearLayout>

strings.xml

<resources>
    <string name="app_name">T8</string>
    <string name="username">用户名:</string>
    <string name="enter_username">请输入用户名</string>
    <string name="password">密码:</string>
    <string name="enter_password">请输入密码</string>
    <string name="login">登录</string>
    <string name="register">注册</string>
    <string name="remember_me">记住我</string>
</resources>

登录后,怎样查看SharedPreferences存储的remember与文件存储的accounts,找到androidstudio的工具栏,点击 View -> Tool Windows -> Device File Explorer 打开,然后找到/data/data/<your.app.package.name>/shared_prefs/与/data/data/<your.app.package.name>/files/,双击即可。

remember.xml文件 

accounts文件

图书馆界面

本题主要为SQLite数据库进行数据存储,也是特别重要的一种存储方式,SQLite数据库在很多设备的应用还是比较多的。

实现一个“网上图书馆”。

需要保存的信息:书本信息和书本所属类别。每本书有其所属的类别。

create table Book (
id integer primary key autoincrement,
author text,
price real,
pages integer,
name text

category_id integer

)

create table Category (
id integer primary key autoincrement
category_name text,
category_code integer)

使用SqlLite数据库创建数据库library,并创建Book和Category这两个表。往Category里插入2条默认书类别数据(如:经济类, 1)。

界面设计:

创建一个MainActivity,对应的布局为activity_main。

添加一个RecyclerView,用于显示所有的图书条目信息,每个条目显示书的名字、作者、类别和价格。

添加一个“添加书目”的按钮,用于跳转进入AddBookActivity。

④ 在AddBookActivity中,可以添加一本书的信息到数据库中。提示:AddBookActivity需要的组件包括:EditText、TextView、Button或Spinner。

提醒:可以在RecyclerView的适配器里面进行数据库的查询操作。

 MainActivity

package com.example.t8

import android.annotation.SuppressLint
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var bookListAdapter: BookListAdapter // 书籍列表的适配器
    private lateinit var emptyView: TextView // 空视图

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 设置 RecyclerView 的布局管理器和适配器
        recyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)
        bookListAdapter = BookListAdapter(getAllBooks())
        recyclerView.adapter = bookListAdapter

        emptyView = findViewById(R.id.emptyTextView)

        // 设置添加书籍按钮的点击事件
        val addBookButton: Button = findViewById(R.id.addBookButton)
        addBookButton.setOnClickListener {
            val intent = Intent(this, AddBookActivity::class.java)
            startActivityForResult(intent, ADD_BOOK_REQUEST_CODE)
        }

        updateBookList()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == ADD_BOOK_REQUEST_CODE && resultCode == RESULT_OK) {
            // 如果是从添加书籍界面返回且成功添加了书籍,则更新书籍列表
            updateBookList()
        }
    }

    private fun updateBookList() {
        val books = getAllBooks()
        bookListAdapter.updateBooks(books)
        checkViewVisibility()
    }

    @SuppressLint("Range")
    private fun getAllBooks(): List<Book> {
        val databaseHelper = DatabaseHelper(this, "library.db", 3)
        val db = databaseHelper.readableDatabase
        val query = "SELECT * FROM Book"
        val cursor = db.rawQuery(query, null)
        val books = mutableListOf<Book>()

        while (cursor.moveToNext()) {
            val id = cursor.getInt(cursor.getColumnIndex("id"))
            val name = cursor.getString(cursor.getColumnIndex("name"))
            val author = cursor.getString(cursor.getColumnIndex("author"))
            val price = cursor.getDouble(cursor.getColumnIndex("price"))
            val pages = cursor.getInt(cursor.getColumnIndex("pages"))
            val categoryId = cursor.getInt(cursor.getColumnIndex("category_id"))

            val book = Book(id, name, author, price, pages, categoryId)
            books.add(book)
        }
        cursor.close()
        return books
    }

    private fun checkViewVisibility() {
        val isEmpty = bookListAdapter.itemCount == 0
        emptyView.visibility = if (isEmpty) View.VISIBLE else View.GONE

        // 控制其他视图的显示/隐藏
        findViewById<TextView>(R.id.BookName).visibility = if (!isEmpty) View.VISIBLE else View.GONE
        findViewById<TextView>(R.id.BookAuthor).visibility = if (!isEmpty) View.VISIBLE else View.GONE
        findViewById<TextView>(R.id.BookPrice).visibility = if (!isEmpty) View.VISIBLE else View.GONE
        findViewById<TextView>(R.id.BookCategory).visibility = if (!isEmpty) View.VISIBLE else View.GONE
    }

    companion object {
        private const val ADD_BOOK_REQUEST_CODE = 1
    }
}

activity_main

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

    <Button
        android:id="@+id/addBookButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="15dp"
        android:text="添加图书" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp">

        <TextView
            android:id="@+id/BookName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="@android:color/black"
            android:textSize="26sp"
            android:textStyle="bold"
            android:text="书名" />

        <TextView
            android:id="@+id/BookAuthor"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="@android:color/black"
            android:textSize="26sp"
            android:textStyle="bold"
            android:text="作者"
            android:visibility="gone" />

        <TextView
            android:id="@+id/BookPrice"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="@android:color/black"
            android:textSize="26sp"
            android:textStyle="bold"
            android:text="价格"
            android:visibility="gone" />

        <TextView
            android:id="@+id/BookCategory"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="@android:color/black"
            android:textSize="26sp"
            android:textStyle="bold"
            android:text="分类"
            android:visibility="gone" />
    </LinearLayout>

    <TextView
        android:id="@+id/emptyTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginTop="300dp"
        android:visibility="gone"
        android:text="暂无图书!"
        android:textSize="20sp" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 Book

package com.example.t8

data class Book(
    val id: Int,
    val name: String,
    val author: String,
    val price: Double,
    val pages: Int,
    val categoryId: Int
)

BookListAdapter

package com.example.t8

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class BookListAdapter(private var bookList: List<Book>) :
    RecyclerView.Adapter<BookListAdapter.BookViewHolder>() {

    class BookViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val nameTextView: TextView = itemView.findViewById(R.id.nameTextView)
        val authorTextView: TextView = itemView.findViewById(R.id.authorTextView)
        val priceTextView: TextView = itemView.findViewById(R.id.priceTextView)
        val categoryTextView: TextView = itemView.findViewById(R.id.categoryTextView)
    }

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

    override fun onBindViewHolder(holder: BookViewHolder, position: Int) {
        val book = bookList[position]
        holder.nameTextView.text = book.name
        holder.authorTextView.text = book.author
        holder.priceTextView.text = book.price.toString()
        holder.categoryTextView.text = book.categoryId.toString()
    }

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

    @SuppressLint("NotifyDataSetChanged")
    fun updateBooks(newBookList: List<Book>) {
        bookList = newBookList
        notifyDataSetChanged()
    }
}

Category

package com.example.t8

data class Category(val id: Int, val categoryName: String, val categoryCode: Int)

CategoryAdapter

class CategoryAdapter(context: Context, private val categories: List<Category>) :
    ArrayAdapter<Category>(context, android.R.layout.simple_spinner_item, categories) {

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = super.getView(position, convertView, parent)
        val textView = view.findViewById<TextView>(android.R.id.text1)
        textView.text = categories[position].categoryName  // 设置下拉框中显示的文本为类别名称
        return view
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = super.getDropDownView(position, convertView, parent)
        val textView = view.findViewById<TextView>(android.R.id.text1)
        textView.text = categories[position].categoryName  // 设置下拉框中下拉选项的文本为类别名称
        return view
    }

    override fun getItem(position: Int): Category? {
        return categories[position] // 返回指定位置的Category对象
    }
}

 item_book.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp">

        <!-- 书名 -->
        <TextView
            android:id="@+id/nameTextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="18sp"
            android:textColor="@android:color/darker_gray" />

        <!-- 作者 -->
        <TextView
            android:id="@+id/authorTextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="18sp"
            android:textColor="@android:color/darker_gray" />

        <!-- 价格 -->
        <TextView
            android:id="@+id/priceTextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="18sp"
            android:textColor="@android:color/darker_gray" />
        <!-- 分类 -->
       <TextView
            android:id="@+id/categoryTextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="18sp"
            android:textColor="@android:color/darker_gray" />
   </LinearLayout>
</LinearLayout>

AddBookActivity

package com.example.t8

import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.*

class AddBookActivity : AppCompatActivity() {

    private lateinit var databaseHelper: DatabaseHelper
    private lateinit var spinnerCategory: Spinner
    private lateinit var categories: List<Category> // 保存类别的列表

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_book)

        // 初始化数据库帮助类
        databaseHelper = DatabaseHelper(this, "library.db", 3)

        insertInitialCategories()

        // 初始化类别选择下拉框
        spinnerCategory = findViewById(R.id.spinnerCategory)
        // 获取所有类别并赋值给 categories
        categories = databaseHelper.getAllCategories()
        // 获取类别名称列表,并将其填充到下拉框中
        val categoryNames = categories.map { it.categoryName }
        val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, categoryNames)
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        spinnerCategory.adapter = adapter

        // 设置添加书籍按钮的点击事件
        val btnAddBook: Button = findViewById(R.id.btnAddBook)
        btnAddBook.setOnClickListener {
            addBook()
        }
    }

    private fun addBook() {
        val editTextName: EditText = findViewById(R.id.editTextName)
        val editTextAuthor: EditText = findViewById(R.id.editTextAuthor)
        val editTextPrice: EditText = findViewById(R.id.editTextPrice)
        val editTextPages: EditText = findViewById(R.id.editTextPages)
        spinnerCategory = findViewById(R.id.spinnerCategory)

        val name = editTextName.text.toString().trim()
        val author = editTextAuthor.text.toString().trim()
        val price = editTextPrice.text.toString().toDoubleOrNull() ?: 0.0
        val pages = editTextPages.text.toString().trim()
        val selectedCategoryName = spinnerCategory.selectedItem as String

        // 根据选择的类别名称,查找对应的 Category 对象
        val selectedCategory = categories.find { it.categoryName == selectedCategoryName }

        // 确保选中的类别不为 null
        selectedCategory?.let {
            val db = databaseHelper.writableDatabase
            val values = ContentValues().apply {
                put("name", name)
                put("author", author)
                put("pages", pages)
                put("price", price)
                put("category_id", it.id) // 使用 selectedCategory 的 id 字段
            }

            // 插入新的书籍记录
            val newRowId = db.insert("Book", null, values)

            if (newRowId != -1L) {
                // 插入成功后,可以添加提示信息或者返回上一界面等操作
                setResult(RESULT_OK)
                finish()
            } else {
                // 插入失败的处理
                Toast.makeText(this, "添加书籍失败", Toast.LENGTH_SHORT).show()
            }
        } ?: run {
            // 如果没有选择类别,提示用户
            Toast.makeText(this, "请选择类别", Toast.LENGTH_SHORT).show()
        }
    }// 插入初始类别数据的方法
    private fun insertInitialCategories() {
        // 检查数据库中是否已经有类别数据
        if (databaseHelper.getAllCategories().isEmpty()) {
            databaseHelper.insertCategory("经济类", 1)
            databaseHelper.insertCategory("武侠类", 2)
            databaseHelper.insertCategory("医药类", 3)
            // 可以根据需要添加更多类别
        }
    }
}

 DatabaseHelper

package com.example.t8

import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

class DatabaseHelper(private val context: Context, name: String, version: Int) : SQLiteOpenHelper(context, name, null, version) {

    // 书本表
    private val createBook = """
        CREATE TABLE Book (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            author TEXT,
            price REAL,
            pages INTEGER,
            name TEXT,
            category_id INTEGER
        )
    """

    // 类别表
    private val createCategory = """
        CREATE TABLE Category (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            category_name TEXT,
            category_code INTEGER
        )
    """

    // 创建数据库时创建表格
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL(createBook)
        db.execSQL(createCategory)
        Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
    }

    // 更新数据库时删除旧表并创建新表
    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS Book")
        db.execSQL("DROP TABLE IF EXISTS Category")
        onCreate(db)
    }

    // 插入类别
    fun insertCategory(categoryName: String, categoryCode: Int) {
        val db = this.writableDatabase
        val contentValues = ContentValues().apply {
            put("category_name", categoryName)
            put("category_code", categoryCode)
        }
        db.insert("Category", null, contentValues)
        db.close()
    }

    // 获取所有类别
    @SuppressLint("Range")
    fun getAllCategories(): List<Category> {
        val categoryList = mutableListOf<Category>()
        val db = this.readableDatabase
        val cursor = db.rawQuery("SELECT * FROM Category", null)
        cursor.use {
            if (it.moveToFirst()) {
                do {
                    val id = it.getInt(it.getColumnIndex("id"))
                    val categoryName = it.getString(it.getColumnIndex("category_name"))
                    val categoryCode = it.getInt(it.getColumnIndex("category_code"))
                    val category = Category(id, categoryName, categoryCode)
                    categoryList.add(category)
                } while (it.moveToNext())
            }
        }
        cursor.close()
        return categoryList
    }
}

activity_add_book.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".AddBookActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:gravity="bottom"
        android:orientation="horizontal">

        <!-- 书名 -->
        <TextView
            android:id="@+id/textViewName"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="16dp"
            android:text="书名"
            android:textSize="23sp" />

        <EditText
            android:id="@+id/editTextName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="start|center_vertical"
            android:layout_marginEnd="16dp"
            android:layout_weight="1"
            android:hint="请输入书名"
            android:inputType="text"
            android:textSize="23sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:gravity="bottom"
        android:orientation="horizontal">

        <!-- 作者 -->
        <TextView
            android:id="@+id/textViewAuthor"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="16dp"
            android:text="作者"
            android:textSize="23sp" />

        <EditText
            android:id="@+id/editTextAuthor"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="start|center_vertical"
            android:layout_marginEnd="16dp"
            android:layout_weight="1"
            android:hint="请输入作者"
            android:inputType="text"
            android:textSize="23sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:gravity="bottom"
        android:orientation="horizontal">

        <!-- 价格 -->
        <TextView
            android:id="@+id/textViewPrice"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="16dp"
            android:text="价格"
            android:textSize="23sp" />

        <EditText
            android:id="@+id/editTextPrice"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="start|center_vertical"
            android:layout_marginEnd="16dp"
            android:layout_weight="1"
            android:hint="请输入价格"
            android:inputType="numberDecimal"
            android:textSize="23sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="bottom"
        android:orientation="horizontal">

        <!-- 页数 -->
        <TextView
            android:id="@+id/textViewPages"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="16dp"
            android:text="页数"
            android:textSize="23sp" />

        <EditText
            android:id="@+id/editTextPages"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="start|center_vertical"
            android:layout_marginEnd="16dp"
            android:layout_weight="1"
            android:hint="请输入页数"
            android:inputType="number"
            android:textSize="23sp" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/layoutCategory"
        android:layout_width="match_parent"
        android:layout_height="58dp"
        android:layout_marginTop="8dp"
        android:background="?android:attr/selectableItemBackground"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:padding="8dp">

        <Spinner
            android:id="@+id/spinnerCategory"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:textSize="23sp" />
    </LinearLayout>

    <!-- 添加书目按钮 -->
    <Button
        android:id="@+id/btnAddBook"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:text="添加书目" />



</LinearLayout>

 AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.t8">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.T8">
        <activity
            android:name=".MainActivity"
            android:exported="false" />
        <activity
            android:name=".AddBookActivity"
            android:exported="false" />
        <activity
            android:name=".LoginActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

然后怎么查看sqlite数据库存储的数据,与上题类似,进到 /data/data/<your.app.package.name>/databases/找到db文件即可。

在这里你会遇到一个问题,怎么双击打不开了,叉掉后进入本地文件夹的存储去了。是的,直接点是打不开的,当你进到文件夹发现这个library文件时拷贝一份,放到你想放的文件夹路径,然后记住这个存放的文件夹路径。接着可以用一些数据库可视化界面管理工具进行连接查看,这里用的是navicat。打开navicat,新建sqlite数据库的连接。

在数据库文件选取你刚刚存放的路径即可,然后就可以查看了。

实验心得

那天,他等到了不下雨,却没有等到天晴。 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2249642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java算法OJ(11)双指针练习

目录 1.前言 2.正文 2.1存在重复数字 2.1.1题目 2.1.2解法一代码 解析&#xff1a; 2.1.3解法二代码 解析&#xff1a; 2.2存在重复数字plus 2.2.1题目 2.2.2代码 2.2.3解析 3.小结 1.前言 哈喽大家好吖&#xff0c;今天来给大家分享双指针算法的相关练习&…

天锐绿盾加密软件与Ping32联合打造企业级安全保护系统,确保敏感数据防泄密与加密管理

随着信息技术的飞速发展&#xff0c;企业在日常经营过程中产生和处理的大量敏感数据&#xff0c;面临着越来越复杂的安全威胁。尤其是在金融、医疗、法律等领域&#xff0c;数据泄漏不仅会造成企业巨大的经济损失&#xff0c;还可能破坏企业的信誉和客户信任。因此&#xff0c;…

Git上传本地项目到远程仓库(gitee/github)

目录 序言一、创建git本地版本库二、连接远程仓库&#xff08;以gitee为例&#xff09;三、将项目提交到git&#xff08;本地&#xff09;版本库1.由工作区添加到暂存区2.由暂存区添加到版本库 四、将代码由本地仓库上传到 gitee远程仓库1.获取远程库与本地同步2.把当前分支 ma…

C7.【C++ Cont】范围for的使用和auto关键字

目录 1.知识回顾 2.范围for 格式 使用 运行结果 运行过程 范围for的本意 作用 注意 3.底层分析范围for的执行过程 反汇编代码 分析 4.auto关键字 格式 基本用法 在范围for中使用auto 1.知识回顾 for循环的使用参见25.【C语言】循环结构之for文章 2.范围for C…

【仓颉学习02】编译后运行报错:“由于找不到libcanjie-runtime.dll,无法继续执行代码。重新安装程序可能会解决此问题。”

敲了段《仓颉语言实践》&#xff08;张磊著&#xff09;书上的代码&#xff0c;如下&#xff1a; package test //coding:utf-8struct Employee{var name:Stringprivate var realSalary:Float64public Employee(name:String,realSalary:Float64){this.namenamethis.realSalary…

AI智算-正式上架GPU资源监控概览 Grafana Dashboard

下载链接 https://grafana.com/grafana/dashboards/22424-ai-gpu-20241127/

LINUX2.4.x网络安全框架

在分析LINUX2.4.x网络安全的实现之前先简介一下它里面包括的几个重要概念&#xff1a;netfilter、iptables、match、target、nf_sockopt_ops、网络安全功能点的实现。详解会在后面的分析中讲到。 首先是netfilter&#xff0c;它定义了协议栈中的检查点和在检查点上引用的数据结…

【博主推荐】C# Winform 拼图小游戏源码详解(附源码)

文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代&#xff0c;程序开…

pytorch错误: 找不到指定的模块 Error loading “torch_python.dll“ or one of its dependencies

省流&#xff1a;python(3.12.7) 和 pytorch(2.4.0)版本不配套 问题 起因是看到了这本书《Build a Large Language Model (From Scratch) 》&#xff0c;是2024年9月新出的&#xff0c; 作者 Sebastian Raschka&#xff0c;想要按照作者给出的步骤来手搓一个大语言模型&#…

渗透测试学习笔记(一)渗透测试方法论

一.渗透测试方法论 渗透测试方法论是制定实施信息安全审计方案时&#xff0c;需要遵循的规则&#xff0c;惯例和过程。人们在评估网络&#xff0c;应用&#xff0c;系统或者三者组合的安全状态时&#xff0c;不断摸索各种实务的理念和成熟的做法&#xff0c;并总结了一套理论-…

【论文阅读】如何高效阅读和理解学术论文

【论文阅读】如何高效阅读和理解学术论文 写在最前面一、为什么需要系统的阅读方法&#xff1f;二、阅读论文的11步方法三、实践示例四、常见问题解答五、结语 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持…

Java 基础面试 题(Java Basic Interview Questions)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

HCIE IGP双栈综合实验

实验拓扑 实验需求及解法 本实验模拟ISP网络结构&#xff0c;R1/2组成国家骨干网&#xff0c;R3/4组成省级网络&#xff0c;R5/6/7组成数据中 心网络。 配置所有ipv4地址&#xff0c;请自行测试直连。 R1 sysname R1 interface GigabitEthernet0/0/0ip address 12.1.1.1 255.…

利用阿里云镜像仓库和 Github Action 同步镜像

利用阿里云镜像仓库和 Github Action 同步镜像 由于某些未知原因,国内无法直接从 DockerHub 拉取镜像,在不使用 VPN 等违法工具的情况下,可以利用 GitHub 的 Action 流水线功能,将镜像推送到阿里云的个人镜像仓库中。 这种方式相较于其他方式虽然相对麻烦,但好在免费,且实…

HarmonyOS4+NEXT星河版入门与项目实战(22)------动画(属性动画与显示动画)

文章目录 1、属性动画图解2、案例实现-小鱼移动游戏1、代码实现2、代码解释3、资源图片4、实现效果3、显示动画4、案例修改-显示动画5、总结1、属性动画图解 这里我们用一张完整的图来汇整属性动画的用法格式和使用的主要属性范围,如下所示: 2、案例实现-小鱼移动游戏 1、代…

csp-j初赛模拟试题(解析)

题目&#xff1a; 在 C中&#xff0c;以下哪个关键字用于实现多态性&#xff1f; A. virtualB. staticC. externD. const 以下数据结构中&#xff0c;不属于线性结构的是&#xff08; &#xff09;。 A. 栈B. 队列C. 二叉树D. 链表 一个有 8 个顶点的无向图&#xff0c;若每个…

使用R的数据包快速获取、调用各种地理数据

数据一直是科学研究绕不开的话题&#xff0c;为了方便快捷的获取各种地理数据&#xff0c;许多R包被开发出来&#xff0c;今天介绍一些方便快捷的数据R包。 rnaturalearth 包使 Natural Earth 数据可用。自然地球特征包括 1&#xff1a;10m、1&#xff1a;50m 和 1&#xff1a…

C语言——指针初阶(一)

目录 一.什么是指针&#xff1f;&#xff1f;&#xff1f; 指针是什么&#xff1f; 指针变量&#xff1a; 总结&#xff1a; 总结&#xff1a; 二.指针和指针类型 指针-整数&#xff1a; 总结&#xff1a; 指针的解引用 总结&#xff1a; 三.野指针 如何规避野指针 往期…

游戏引擎学习第22天

移除 DllMain() 并成功重新编译 以下是对内容的详细复述与总结&#xff1a; 问题和解决方案&#xff1a; 在编译过程中遇到了一些问题&#xff0c;特别是如何告知编译器不要退出程序&#xff0c;而是继续处理。问题的根源在于编译过程中传递给链接器的参数设置不正确。原本尝试…

Paper -- 建筑物高度估计 -- 使用街景图像、深度学习、轮廓处理和地理空间数据的建筑高度估计

基本信息 论文题目: Building Height Estimation using Street-View Images, Deep-Learning, Contour Processing, and Geospatial Data 中文题目: 使用街景图像、深度学习、轮廓处理和地理空间数据的建筑高度估计 作者: Ala’a Al-Habashna 作者单位: 加拿大统计局特别商业项…