目录
1. 用户登陆界面
(
1
) 创建一个
LoginActivity
,对应的布局文件
activity_login
。
(
2
) 具备两个
TextView
和两个
EditText
控件,分别用于显示和输入用户名和密码。
(
3
) 添加
“
注册
”
和
“
登陆
”
两个按钮(
Button
)。
(
4
) 添加
“
记住我
”
功能:插入一个
CheckBox
控件,当用户勾选该勾选框,当点击
“
登陆
”
按钮时,判断该勾选框,如果勾选,则把用户名和密码保存起来,要求采用文本存储方式保
存下来。
(
5
) 点击
“
注册
”
,可以根据用户名和密码对应的
EditText
,将用户名和密码保存起来,
要求采用
SharedPreferences
保存用户名和密码数据,同时需要确保用户名不重复(区分
大小写)。
(
6
) 点击
“
登陆
”
,通过
SharedPreferences
读取用户密码数据,并进行匹配,只有匹
配成功,才能成功登陆,跳转到
MainActivity
(下一个设计内容)
2. 图书信息数据库和显示界面
(
1
) 需要保存的信息:书本信息(下表左),和书本所属类别(下表右)。每本书有其
所属的类别。
create table Book ( category_id integer ) | create table Category ( |
使用
SqlLite
数据库创建数据库
library
,并创建
Book
和
Category
这两个表。往
Category
里插入
2
条默认书类别数据(如:经济类,
1
)。
(
2
) 界面设计:
① 创建一个
MainActivity
,对应的布局为
activity_main
。
② 添加一个
RecyclerView
,用于显示所有的图书条目信息,每个条目显示书的名字、
作者、类别和价格。
③ 添加一个
“
添加书目
”
的按钮,用于跳转进入
AddBookActivity
。
④ 在
AddBookActivity
中 , 可 以 添 加 一 本 书 的 信 息 到 数 据 库 中 。 提 示 :
AddBookActivity 需要的组件包括:
EditText
、
TextView
、
Button
或
Spinner
。
提醒:可以在 RecyclerView
的适配器里面进行数据库的查询操作。
3.应用运行功能的截图
登录、注册、检查重名、检查账户密码是否正确、密码是否正确、记住密码
![](https://i-blog.csdnimg.cn/direct/80bf81390ab74304a7944415f4d6d393.png)
![](https://i-blog.csdnimg.cn/direct/1784d6c002e843769d18096e28c033e2.png)
![](https://i-blog.csdnimg.cn/direct/d75a7a06e078470b8cca2518f49b1699.png)
登录成功后进入首页面:
![](https://i-blog.csdnimg.cn/direct/ed39c3987c4a49ed98d9138705cdbf28.png)
![](https://i-blog.csdnimg.cn/direct/2870b928336345caa3a6a2ae7e09aa78.png)
4.源码
Book.kt
data class
Book(
val
author
: String
,
val
price
: Double
,
val
pages
: Int
,
val
name
: String
,
val
categoryId
: Int
)
Category.kt
package
com.example.mylibrary
data class
Category(
val
id
: Int
,
val
categoryName
: String
,
val
categoryCode
: Int
)
LoginActivity.kt
package
com.example.mylibrary
import
android.content.Context
import
android.content.Intent
import
android.content.SharedPreferences
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
class
LoginActivity : AppCompatActivity() {
private lateinit var
usernameEditText
: EditText
private lateinit var
passwordEditText
: EditText
private lateinit var
rememberMeCheckBox
: CheckBox
private lateinit var
sharedPreferences
: SharedPreferences
override fun
onCreate
(savedInstanceState: Bundle?) {
super
.onCreate(savedInstanceState)
setContentView(R.layout.
activity_login
)
usernameEditText
= findViewById(R.id.
usernameEditText
)
passwordEditText
= findViewById(R.id.
passwordEditText
)
rememberMeCheckBox
= findViewById(R.id.
rememberMeCheckBox
)
val
loginButton: Button = findViewById(R.id.
loginButton
)
val
registerButton: Button = findViewById(R.id.
registerButton
)
sharedPreferences
= getSharedPreferences(
"MyPrefs"
,
Context.
MODE_PRIVATE
)
loginButton.setOnClickListener
{
val
username =
usernameEditText
.
text
.toString()
val
password =
passwordEditText
.
text
.toString()
if
(validateLogin(username
,
password)) {
if
(
rememberMeCheckBox
.
isChecked
) {
rememberUser(username
,
password)
}
val
intent = Intent(
this
@LoginActivity
,
MainActivity::
class
.
java
)
startActivity(intent)
//
finish()
}
else
{
Toast.makeText(
this
@LoginActivity
,
"Invalid username or
password"
,
Toast.
LENGTH_SHORT
).show()
}
}
registerButton.setOnClickListener
{
val
username =
usernameEditText
.
text
.toString()
val
password =
passwordEditText
.
text
.toString()
if
(registerUser(username
,
password)) {
Toast.makeText(
this
@LoginActivity
,
"Registration
successful"
,
Toast.
LENGTH_SHORT
).show()
}
else
{
Toast.makeText(
this
@LoginActivity
,
"Username already
exists"
,
Toast.
LENGTH_SHORT
).show()
}
}
}
private fun
validateLogin
(username: String
,
password: String): Boolean
{
val
storedPassword =
sharedPreferences
.getString(username
, null
)
return
storedPassword == password
}
private fun
rememberUser
(username: String
,
password: String) {
val
editor =
sharedPreferences
.edit()
editor.putString(username
,
password)
editor.apply()
}
private fun
registerUser
(username: String
,
password: String): Boolean {
if
(!
sharedPreferences
.contains(username)) {
val
editor =
sharedPreferences
.edit()
editor.putString(username
,
password)
editor.apply()
return true
}
return false
}
}
activity_login.xml
<?
xml version
="1.0"
encoding
="utf-8"
?>
<RelativeLayout
xmlns:
android
="http://schemas.android.com/apk/res/android"
android
:layout_width
="match_parent"
android
:layout_height
="match_parent"
android
:padding
="16dp"
>
<TextView
android
:id
="@+id/usernameTextView"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:text
="Username"
android
:layout_marginBottom
="8dp"
/>
<EditText
android
:id
="@+id/usernameEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:layout_below
="@id/usernameTextView"
android
:hint
="Enter username"
android
:padding
="12dp"
10
android
:layout_marginBottom
="16dp"
/>
<TextView
android
:id
="@+id/passwordTextView"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:layout_below
="@id/usernameEditText"
android
:text
="Password"
android
:layout_marginBottom
="8dp"
/>
<EditText
android
:id
="@+id/passwordEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:layout_below
="@id/passwordTextView"
android
:inputType
="textPassword"
android
:hint
="Enter password"
android
:padding
="12dp"
android
:layout_marginBottom
="16dp"
/>
<CheckBox
android
:id
="@+id/rememberMeCheckBox"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:text
="Remember me"
android
:layout_below
="@id/passwordEditText"
android
:layout_marginBottom
="16dp"
/>
<Button
android
:id
="@+id/loginButton"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:text
="Login"
android
:layout_below
="@id/rememberMeCheckBox"
android
:layout_marginBottom
="8dp"
/>
<Button
android
:id
="@+id/registerButton"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:text
="Register"
android
:layout_below
="@id/loginButton"
/>
</RelativeLayout>
MainActivity.kt
package
com.example.mylibrary
import
android.content.Intent
import
android.os.Bundle
import
android.view.View
import
android.widget.Button
import
android.widget.TextView
import
androidx.appcompat.app.AppCompatActivity
import
androidx.recyclerview.widget.LinearLayoutManager
import
androidx.recyclerview.widget.RecyclerView
class
MainActivity : AppCompatActivity() {
private lateinit var
recyclerView
: RecyclerView
private lateinit var
bookAdapter
: BookAdapter
private lateinit var
emptyView
: TextView
override fun
onCreate
(savedInstanceState: Bundle?) {
super
.onCreate(savedInstanceState)
setContentView(R.layout.
activity_main
)
recyclerView
= findViewById(R.id.
recyclerView
)
recyclerView
.
layoutManager
= LinearLayoutManager(
this
)
bookAdapter
= BookAdapter(getAllBooksFromDatabase())
recyclerView
.
adapter
=
bookAdapter
checkEmptyViewVisibility()
//
val dbHelper = DatabaseHelper(this, "BookStore.db", 2)
//
val createDatabase =
findViewById<Button>(R.id.createDatabase)
//
createDatabase.setOnClickListener {
//
dbHelper.writableDatabase
//
}
val
addData = findViewById<Button>(R.id.
addData
)
addData.setOnClickListener
{
val
intent = Intent(
this
@MainActivity
,
AddBookActivity::
class
.
java
)
startActivity(intent)
}
}
private fun
getAllBooksFromDatabase
(): List<Book> {
val
dbHelper = DatabaseHelper(
this,
"BookStore.db"
,
2
)
val
db = dbHelper.
readableDatabase
val
query =
"SELECT * FROM Book"
val
cursor = db.rawQuery(query
, null
)
val
books =
mutableListOf
<Book>()
while
(cursor.moveToNext()) {
val
nameIndex = cursor.getColumnIndex(
"name"
)
val
authorIndex = cursor.getColumnIndex(
"author"
)
val
priceIndex = cursor.getColumnIndex(
"price"
)
val
categoryIdIndex =
cursor.getColumnIndex(
"categoryId"
)
val
name: String? = cursor.getString(nameIndex)
val
author: String? = cursor.getString(authorIndex)
val
price: Double = cursor.getDouble(priceIndex)
val
categoryId: Int = cursor.getInt(categoryIdIndex)
//
使用空字符串作为默认值
val
book = Book(author ?:
""
,
price
,
0
,
name ?:
""
,
categoryId)
books.add(book)
}
cursor.close()
return
books
}
private fun
checkEmptyViewVisibility
() {
emptyView
= findViewById(R.id.
emptyTextView
)
if
(
bookAdapter
.
itemCount
==
0
) {
emptyView
.
visibility
= View.
VISIBLE
}
else
{
emptyView
.
visibility
= View.
GONE
}
}
}
activity_main.xml
<?
xml version
="1.0"
encoding
="utf-8"
?>
<LinearLayout
xmlns:
android
="http://schemas.android.com/apk/res/android"
android
:orientation
="vertical"
android
:layout_width
="match_parent"
android
:layout_height
="match_parent"
>
<androidx.recyclerview.widget.RecyclerView
android
:id
="@+id/recyclerView"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:layout_weight
="1"
android
:scrollbars
="vertical"
/>
<TextView
android
:id
="@+id/emptyTextView"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:gravity
="center"
android
:visibility
="gone"
android
:text
="No books available"
android
:textSize
="20sp"
/>
<!--
<Button-->
<!--
android:id="@+id/createDatabase"-->
<!--
android:layout_width="match_parent"-->
<!--
android:layout_height="wrap_content"-->
<!--
android:text="Create Database" />-->
<Button
android
:id
="@+id/addData"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:text
="Add Book"
/>
<!--
<TextView-->
<!--
android:id="@+id/androidTextView"-->
<!--
android:layout_width="wrap_content"-->
<!--
android:layout_height="wrap_content"-->
<!--
android:text="Android Text" />-->
<!--
<Button-->
<!--
android:id="@+id/updateData"-->
<!--
android:layout_width="match_parent"-->
<!--
android:layout_height="wrap_content"-->
<!--
android:text="Update Data" />-->
<!--
<Button-->
<!--
android:id="@+id/deleteData"-->
<!--
android:layout_width="match_parent"-->
<!--
android:layout_height="wrap_content"-->
<!--
android:text="Delete Data" />-->
<!--
<Button-->
15
<!--
android:id="@+id/queryData"-->
<!--
android:layout_width="match_parent"-->
<!--
android:layout_height="wrap_content"-->
<!--
android:text="Query Data"/>-->
</LinearLayout>
DataBaseHelper.kt
package
com.example.mylibrary
import
android.content.ContentValues
import
android.content.Context
import
android.database.sqlite.SQLiteDatabase
import
android.database.sqlite.SQLiteOpenHelper
import
android.widget.Toast
class
DatabaseHelper(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,"
+
"categoryId 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(this@DatabaseHelper, "Tables created
successfully", Toast.LENGTH_SHORT).show()
//
插入经济类别记录
val
contentValues = ContentValues().
apply
{
put(
"category_name"
,
"
经济类
"
)
put(
"category_code"
,
1
)
}
16
db.insert(
"Category"
, null,
contentValues)
}
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)
}
}
AddBookActivity.kt
package
com.example.mylibrary
import
android.content.ContentValues
import
android.content.Intent
import
android.os.Bundle
import
android.widget.Button
import
android.widget.EditText
import
android.widget.Toast
import
androidx.appcompat.app.AppCompatActivity
class
AddBookActivity : AppCompatActivity() {
//
private lateinit var dbHelper: DatabaseHelper
override fun
onCreate
(savedInstanceState: Bundle?) {
super
.onCreate(savedInstanceState)
setContentView(R.layout.
activity_add_book
)
//
dbHelper = DatabaseHelper(this)
val
dbHelper =DatabaseHelper(
this,
"BookStore.db"
,
2
)
val
addBookButton: Button = findViewById(R.id.
addBookButton
)
addBookButton.setOnClickListener
{
val
nameEditText: EditText = findViewById(R.id.
nameEditText
)
val
authorEditText: EditText = findViewById(R.id.
authorEditText
)
//
val category: EditText =
findViewById(R.id.categoryIdEditText)
val
priceEditText: EditText = findViewById(R.id.
priceEditText
)
val
categoryIdEditText: EditText =
findViewById(R.id.
categoryIdEditText
)
val
name = nameEditText.
text
.toString()
val
author = authorEditText.
text
.toString()
17
//
val pages = pagesEditText.text.toString().toIntOrNull() ?: 0
//
处理无效输入
val
price = priceEditText.
text
.toString().
toDoubleOrNull
() ?:
0.0
//
处理无效输入
val
categoryId =
categoryIdEditText.
text
.toString().
toIntOrNull
() ?:
0
//
处理无效输入
val
db = dbHelper.
writableDatabase
val
values = ContentValues().
apply
{
put(
"name"
,
name)
put(
"author"
,
author)
put(
"categoryId"
,
categoryId)
put(
"price"
,
price)
//
put("categoryId", categoryId)
}
val
newRowId = db.insert(
"Book"
, null,
values)
if
(newRowId == -
1L
) {
//
插入失败
Toast.makeText(
this,
"
添加书籍到数据库失败
"
,
Toast.
LENGTH_SHORT
).show()
}
else
{
//
插入成功
Toast.makeText(
this,
"
书籍已添加到数据库
"
,
Toast.
LENGTH_SHORT
).show()
}
//
清空输入框
nameEditText.
text
.clear()
authorEditText.
text
.clear()
categoryIdEditText.
text
.clear()
priceEditText.
text
.clear()
//
categoryIdEditText.text.clear()
val
intent = Intent(
this
@AddBookActivity
,
MainActivity::
class
.
java
)
startActivity(intent)
//
finish();
}
}
}
activity_add_book.xml
<?
xml version
="1.0"
encoding
="utf-8"
?>
<RelativeLayout
xmlns:
android
="http://schemas.android.com/apk/res/android"
android
:layout_width
="match_parent"
android
:layout_height
="match_parent"
android
:padding
="16dp"
>
<EditText
android
:id
="@+id/authorEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:hint
="Author"
android
:layout_marginBottom
="16dp"
android
:minWidth
="200dp"
android
:minHeight
="48dp"
android
:padding
="8dp"
/>
<EditText
android
:id
="@+id/priceEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:inputType
="numberDecimal"
android
:hint
="Price"
android
:layout_below
="@id/authorEditText"
android
:layout_marginBottom
="16dp"
android
:minWidth
="200dp"
android
:minHeight
="48dp"
android
:padding
="8dp"
/>
<EditText
android
:id
="@+id/pagesEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:inputType
="number"
android
:hint
="Pages"
android
:layout_below
="@id/priceEditText"
android
:layout_marginBottom
="16dp"
android
:minWidth
="200dp"
android
:minHeight
="48dp"
android
:padding
="8dp"
/>
<EditText
android
:id
="@+id/nameEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
18
android
:hint
="Name"
android
:layout_below
="@id/pagesEditText"
android
:layout_marginBottom
="16dp"
android
:minWidth
="200dp"
android
:minHeight
="48dp"
android
:padding
="8dp"
/>
<EditText
android
:id
="@+id/categoryIdEditText"
android
:layout_width
="match_parent"
android
:layout_height
="wrap_content"
android
:inputType
="number"
android
:hint
="Category ID"
android
:layout_below
="@id/nameEditText"
android
:layout_marginBottom
="16dp"
android
:minWidth
="200dp"
android
:minHeight
="48dp"
android
:padding
="8dp"
/>
<Button
android
:id
="@+id/addBookButton"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:text
="Add Book"
android
:layout_centerInParent
="true"
/>
<androidx.recyclerview.widget.RecyclerView
android
:id
="@+id/recyclerView"
android
:layout_width
="match_parent"
android
:layout_height
="match_parent"
android
:layout_above
="@id/addBookButton"
android
:layout_marginBottom
="16dp"
/>
</RelativeLayout>
BookAdapter.kt
// BookAdapter.kt
package
com.example.mylibrary
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.widget.TextView
import
androidx.recyclerview.widget.RecyclerView
class
BookAdapter(
private val
bookList
: List<Book>) :
RecyclerView.Adapter<BookAdapter.BookViewHolder>() {
class
BookViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
val
titleTextView
: TextView =
itemView.findViewById(R.id.
textViewTitle
)
val
authorTextView
: TextView =
itemView.findViewById(R.id.
textViewAuthor
)
val
categoryTextView
: TextView =
itemView.findViewById(R.id.
textViewCategory
)
val
priceTextView
: TextView =
itemView.findViewById(R.id.
textViewPrice
)
}
override fun
onCreateViewHolder
(parent: ViewGroup
,
viewType: Int):
BookViewHolder {
val
itemView = LayoutInflater.from(parent.
context
)
.inflate(R.layout.
item_book
,
parent
, false
)
return
BookViewHolder(itemView)
}
override fun
onBindViewHolder
(holder: BookViewHolder
,
position: Int) {
val
currentItem =
bookList
[position]
holder.
titleTextView
.
text
= currentItem.
name
holder.
authorTextView
.
text
= currentItem.
author
holder.
categoryTextView
.
text
= currentItem.
categoryId
.toString()
holder.
priceTextView
.
text
= currentItem.
price
.toString()
}
override fun
getItemCount
() =
bookList
.
size
}
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"
>
<TextView
android
:id
="@+id/textViewTitle"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:textSize
="18sp"
android
:textStyle
="bold"
android
:text
="Title"
/>
<TextView
android
:id
="@+id/textViewAuthor"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:textSize
="16sp"
android
:text
="Author"
/>
<TextView
android
:id
="@+id/textViewCategory"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:textSize
="14sp"
android
:text
="Category"
/>
<TextView
android
:id
="@+id/textViewPrice"
android
:layout_width
="wrap_content"
android
:layout_height
="wrap_content"
android
:textSize
="14sp"
android
:text
="Price"
/>
</LinearLayout>