zoukankan      html  css  js  c++  java
  • 【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()
                        }
                    }
    
    
                })
    
            }
        }
    
    
    }
    

      

    运行结果

  • 相关阅读:
    回溯、递归、DFS方法
    3-11日学习记录
    文本清洗总结
    归并排序学习
    3-9日学习笔记
    P3182 [HAOI2016]放棋子 错排问题
    P2880 [USACO07JAN]平衡的阵容Balanced Lineup 线段树 树状数组
    P3469 [POI2008]BLO-Blockade 强连通
    P2756 飞行员配对方案问题 网络流 二分图匹配
    P1823 [COI2007] Patrik 音乐会的等待 单调栈
  • 原文地址:https://www.cnblogs.com/leftstan/p/14500928.html
Copyright © 2011-2022 走看看