【Android Studio】图书管理系统——功能实现原理

使用框架

采用了MVVM框架,即Model View ViewModel模式

Model:接收后端发送的实体数据

ViewModel:处理Model的数据并发送给View

View:展示处理好的数据

 

 

 

项目结构

 

 

 

 

具体实例

逻辑层

在ReaderClientApplication.kt文件中定义token以及一个全局context

class ReaderClientApplication: Application() {
     var TOKEN = ""
    companion object{
        @SuppressLint("StaticFieldLeak")
        lateinit var context: Context
    }

    override fun onCreate() {
        super.onCreate()
        context = applicationContext
        TOKEN = TOKEN
    }
}

 同时还需要在AndroidManifest.xml中注册

<application
        android:name=".ReaderClientApplication"
        android:allowBackup="true"
        android:icon="@drawable/logo"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    .......
</application>

  

根据返回的json格式,定义数据模型

model中的UserResponse.kt

data class UserResponse (val code: String, val data: UserData, val msg: String)

data class UserData(val admin: Int, val borrowCount: Int, val major: String, val password: String, val sno: String, val username: String)

data class User(val sno: String, val password: String)

  

定义访问后端提供的API的接口

network中的BookService

interface BookService {
    @POST("user/login")
    fun loginValidate(@Body user: User ): Call<UserResponse>

......//其它接口

}

  

创建Retrofit构建器

network中的ServiceCreator

package com.example.readerclient.logic.network

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object ServiceCreator {
    //后端服务基础地址
    private const val BASE_URL = "http://172.27.183.4:8080/aissm_war_exploded/"

    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    fun<T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)

    inline fun <reified T> create(): T = create(T::class.java)


}

 

定义统一网络数据源 访问入口

object ReaderClientNetwork {
    private val BookService = ServiceCreator.create(BookService::class.java)

    suspend fun loginValidate(sno: String, password: String) = BookService.loginValidate(User(sno, password)).await()

......//其它方法

    private suspend fun <T> Call<T>.await(): T{
        return suspendCoroutine {
                continuation -> enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                val body = response.body()

                if(body != null) continuation.resume(body)
                else continuation.resumeWithException(
                    RuntimeException("response body is null")
                )
            }

            override fun onFailure(call: Call<T>, t: Throwable) {
                continuation.resumeWithException(t)
            }
        })
        }
    }

}

  

创建仓库层的统一封装入口

Repository单例类

object Repository {
    fun loginValidate(sno: String, password: String) = liveData(Dispatchers.IO){
        //var userResponse = UserResponse("", UserData(0, 0 ,"", "", "", ""), "")
        val result = try{
            val userResponse = ReaderClientNetwork.loginValidate(sno, password)
            if(userResponse.code == "0") {
                Result.success(userResponse)
            }else{
                Result.failure(RuntimeException("Response status is ${userResponse.code}, msg: ${userResponse.msg}"))
            }
        }catch(e: Exception){
            Result.failure<List<String>>(e)
        }
        //Log.d("userResponse code is:", result.toString())
        //Log.d("userResponse code is:", userResponse.toString())
        emit(result)
    }

......//其它方法
}

  

定义ViewModel层

ui/login中的UserViewModel

class UserViewModel: ViewModel() {
    private val loginLiveData = MutableLiveData<User>()

    val userLiveData = Transformations.switchMap(loginLiveData){
        user -> Repository.loginValidate(user.sno, user.password)
    }


    fun loginValidate(sno: String, password: String){
        loginLiveData.value = User(sno, password)
    }

}

  

UI层

创建activity_login.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.login.LoginActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:paddingTop="50dp"
        android:paddingBottom="50dp"
        app:srcCompat="@drawable/logo" />

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

        <TextView
            android:id="@+id/account"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="账号" />

        <EditText
            android:id="@+id/accountEdit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="textPersonName" />

    </LinearLayout>

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

        <TextView
            android:id="@+id/password"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码" />

        <EditText
            android:id="@+id/passwordEdit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="textPassword" />

    </LinearLayout>

    <Button
        android:id="@+id/loginBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录" />
</LinearLayout>

 

创建LoginActivity文件

class LoginActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        val viewModel by lazy{ ViewModelProviders.of(this).get(UserViewModel::class.java)}
        val prefs = getSharedPreferences("data", Context.MODE_PRIVATE)
        var today = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
        var lastday = prefs.getInt("lastday", today)
        var attempt = prefs.getInt("attempt", 0)
        accountEdit.setText(prefs.getString("account", ""))
        //Toast.makeText(this, "${today}   ${lastday}", Toast.LENGTH_SHORT).show()
        //判断今日密码输入次数
        if(today == lastday)
        {
            if( attempt >= 100) {
                Toast.makeText(this, "已达今天最大尝试次数,请再重试", Toast.LENGTH_SHORT).show()
                this.finish()
            }
        }else{
            attempt = 0
            lastday = today
        }
        var flag = 1
        //登录按钮

        loginBtn.setOnClickListener(){

            val account = accountEdit.text.toString()
            val password = passwordEdit.text.toString()
            val editor = prefs.edit()
            val intent = Intent(this, MainActivity::class.java)
            var userResponse : UserResponse

            editor.putInt("lastday", lastday)
            viewModel.loginValidate(account, password)
            viewModel.userLiveData.observe(this, Observer{
                    result ->
                if(result.getOrNull() != null){
                    userResponse = result.getOrNull() as UserResponse
                    Log.d("testing",result.toString())
                    Log.d("testing",userResponse.toString())
                    editor.putString("account", account)
                    if(userResponse.code.toInt() == 0){
                        editor.putString("token", userResponse.msg)
                        val user = userResponse.data
                        if(password == user.password) {
                            editor.putString("name", user.username)
                            editor.putString("sno", user.sno)
                            editor.putString("major", user.major)
                            editor.apply()
                            this.finish()
                            startActivity(intent)
                        }
                    }
                    else{
                        Toast.makeText(this, userResponse.msg, Toast.LENGTH_SHORT).show()
                    }
                }


            })

        }
    }


}

  

运行结果

 

posted @ 2021-03-08 20:31  Left_Stan  阅读(1048)  评论(0编辑  收藏  举报