又是学到了数据持久化。
登录界面
题外话:有无动画大佬带带呀,前端移动端可免( •̀ .̫ •́ ),合作可私信哦。
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.t8import 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.AlertDialogclass 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)// 获取 SharedPreferencesval 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()// 登录成功,跳转到 MainActivityval 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) --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="80dp"android:orientation="horizontal"android:gravity="bottom"><TextViewandroid: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" /><EditTextandroid: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) --><LinearLayoutandroid:layout_width="match_parent"android:layout_height="80dp"android:orientation="horizontal"android:gravity="bottom"><TextViewandroid: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" /><EditTextandroid: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) --><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><CheckBoxandroid:id="@+id/rememberMe"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="17dp"android:layout_marginStart="25dp" /><TextViewandroid: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) --><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="16dp"android:layout_gravity="center"><Buttonandroid:id="@+id/login"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/login"android:textSize="24sp"android:layout_margin="10dp" /><Buttonandroid: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 ( category_id integer ) | create table Category ( |
使用SqlLite数据库创建数据库library,并创建Book和Category这两个表。往Category里插入2条默认书类别数据(如:经济类, 1)。
界面设计:
创建一个MainActivity,对应的布局为activity_main。
添加一个RecyclerView,用于显示所有的图书条目信息,每个条目显示书的名字、作者、类别和价格。
添加一个“添加书目”的按钮,用于跳转进入AddBookActivity。
④ 在AddBookActivity中,可以添加一本书的信息到数据库中。提示:AddBookActivity需要的组件包括:EditText、TextView、Button或Spinner。
提醒:可以在RecyclerView的适配器里面进行数据库的查询操作。
MainActivity
package com.example.t8import 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.RecyclerViewclass MainActivity : AppCompatActivity() {private lateinit var recyclerView: RecyclerViewprivate 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 = bookListAdapteremptyView = 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.readableDatabaseval 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 == 0emptyView.visibility = if (isEmpty) View.VISIBLE else View.GONE// 控制其他视图的显示/隐藏findViewById<TextView>(R.id.BookName).visibility = if (!isEmpty) View.VISIBLE else View.GONEfindViewById<TextView>(R.id.BookAuthor).visibility = if (!isEmpty) View.VISIBLE else View.GONEfindViewById<TextView>(R.id.BookPrice).visibility = if (!isEmpty) View.VISIBLE else View.GONEfindViewById<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"><Buttonandroid:id="@+id/addBookButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="15dp"android:text="添加图书" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="16dp"><TextViewandroid: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="书名" /><TextViewandroid: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" /><TextViewandroid: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" /><TextViewandroid: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><TextViewandroid: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.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>
Book
package com.example.t8data class Book(val id: Int,val name: String,val author: String,val price: Double,val pages: Int,val categoryId: Int
)
BookListAdapter
package com.example.t8import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerViewclass 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.nameholder.authorTextView.text = book.authorholder.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 = newBookListnotifyDataSetChanged()}
}
Category
package com.example.t8data 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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:padding="16dp"><!-- 书名 --><TextViewandroid: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" /><!-- 作者 --><TextViewandroid: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" /><!-- 价格 --><TextViewandroid: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" /><!-- 分类 --><TextViewandroid: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.t8import android.content.ContentValues
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.*class AddBookActivity : AppCompatActivity() {private lateinit var databaseHelper: DatabaseHelperprivate lateinit var spinnerCategory: Spinnerprivate 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)// 获取所有类别并赋值给 categoriescategories = 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.0val pages = editTextPages.text.toString().trim()val selectedCategoryName = spinnerCategory.selectedItem as String// 根据选择的类别名称,查找对应的 Category 对象val selectedCategory = categories.find { it.categoryName == selectedCategoryName }// 确保选中的类别不为 nullselectedCategory?.let {val db = databaseHelper.writableDatabaseval 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.t8import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toastclass 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.writableDatabaseval 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.readableDatabaseval 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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="80dp"android:gravity="bottom"android:orientation="horizontal"><!-- 书名 --><TextViewandroid: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" /><EditTextandroid: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><LinearLayoutandroid:layout_width="match_parent"android:layout_height="80dp"android:gravity="bottom"android:orientation="horizontal"><!-- 作者 --><TextViewandroid: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" /><EditTextandroid: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><LinearLayoutandroid:layout_width="match_parent"android:layout_height="80dp"android:gravity="bottom"android:orientation="horizontal"><!-- 价格 --><TextViewandroid: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" /><EditTextandroid: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><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="bottom"android:orientation="horizontal"><!-- 页数 --><TextViewandroid: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" /><EditTextandroid: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><LinearLayoutandroid: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"><Spinnerandroid:id="@+id/spinnerCategory"android:layout_width="match_parent"android:layout_height="48dp"android:textSize="23sp" /></LinearLayout><!-- 添加书目按钮 --><Buttonandroid: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"><applicationandroid: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"><activityandroid:name=".MainActivity"android:exported="false" /><activityandroid:name=".AddBookActivity"android:exported="false" /><activityandroid: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数据库的连接。
在数据库文件选取你刚刚存放的路径即可,然后就可以查看了。
实验心得
那天,他等到了不下雨,却没有等到天晴。