使用视图模型和改造的用户登录 [英] user login using viewmodel and retrofit

查看:21
本文介绍了使用视图模型和改造的用户登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用改造和视图模型进行登录

我仅通过改造就成功登录...参考本教程-->

在登录活动中:-1-->

2-->

3-->

解决方案

class LoginActivity : BaseClassActivity() {私有 val viewModel by viewModels()覆盖 fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.login_activity)val button = findViewById(R.id.plusbutton)val forgotpassword = findViewById(R.id.forgotpassword)button.setOnClickListener {val i = Intent(applicationContext, RegisterActivity::class.java)开始活动(i)}忘记密码.setOnClickListener {val i = Intent(applicationContext, ForgotPassword::class.java)开始活动(i)}loginuser.onTextChanged {viewModel.user.value = it.toString()}loginpassword.onTextChanged {viewModel.password.value = it.toString()}loginbtn.setOnClickListener {viewModel.login()}viewModel.loginResult.observe(this) { result ->当(结果){UserMissing ->{Toast.makeText(applicationContext,数据丢失",Toast.LENGTH_LONG).展示()loginuser.error = "需要电子邮件";loginuser.requestFocus()}密码丢失 ->{loginpassword.error = "需要密码";登录密码.requestFocus()}网络故障 ->{}网络错误 ->{showToast(applicationContext, result.userMessage)}成功 ->{val 意图 = 意图(applicationContext,HomeActivity::class.java)意图.标志 =Intent.FLAG_ACTIVITY_NEW_TASK 或 Intent.FLAG_ACTIVITY_CLEAR_TASKshowToast(applicationContext, res.body()?.message)Log.d(kjsfgxhufb", response.body()?.status.toString())开始活动(意图)结束()}}.安全的()}}}类 LoginViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {密封类 LoginResult {对象 UserMissing : LoginResult(),对象 PasswordMissing : LoginResult(),类 NetworkError(val userMessage: String) : LoginResult(),对象 NetworkFailure : LoginResult(),对象成功:LoginResult()}val 用户:MutableLiveData= savedStateHandle.getLiveData("user", "")val 密码:MutableLiveData= savedStateHandle.getLiveData("密码", "")private val loginResultEmitter = EventEmitter()val loginResult: EventSource= loginResultEmitter有趣的登录(){val email = user.value!!.toString().trim()val 密码 = password.value!!.toString().trim()如果 (email.isEmpty()) {loginResultEmitter.emit(LoginResult.UserMissing)返回}如果(密码.isEmpty()){loginResultEmitter.emit(LoginResult.PasswordMissing)返回}RetrofitClient.instance.userLogin(email, password).enqueue(对象:回调<登录响应>{覆盖 fun onFailure(call: Call, t: Throwable) {Log.d("res", "" + t)loginResultEmitter.emit(LoginResult.NetworkFailure)}覆盖乐趣 onResponse(呼叫:呼叫<登录响应>,响应:响应<登录响应>){var res = 响应Log.d("响应检查", "" + response.body()?.status.toString())如果 (res.body()?.status == 200) {SharedPrefManager.getInstance(applicationContext).saveUser(response.body()?.data!!)loginResultEmitter.emit(LoginResult.Success)} 别的 {尝试 {val jObjError =JSONObject(response.errorBody()!!.string())loginResultEmitter.emit(LoginResult.NetworkError(jObjError.getString("user_msg")))} catch (e: 异常) {//showToast(applicationContext,e.message)//TODOLog.e("errorrr", e.message)}}}})}}

使用这个库(我写这个是因为没有,现在仍然没有任何其他库可以在不使用 SingleLiveEvent 的反模式或事件包装器的情况下正确解决这个问题)

所有项目{存储库{//...maven { url "https://jitpack.io";}}//...}实现 'com.github.Zhuinden:live-event:1.1.0'

一些缺失的块来实际编译:

有趣的T.safe(): T = this//辅助方法

Gradle 中的这些依赖

实现androidx.core:core-ktx:1.3.2";实现androidx.activity:activity-ktx:1.1.0";实现androidx.fragment:fragment-ktx:1.2.5";实现androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0";

同时添加

android {编译选项{sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}科特林选项{jvmTarget = 1.8"}}

要访问 ViewModel 中的 applicationContext,您需要使用 AndroidViewModel 而不是 ViewModel

class LoginViewModel(私人 val 应用程序:应用程序,私有 val 保存状态句柄:保存状态句柄):AndroidViewModel(应用程序){私有 val applicationContext = 应用程序

那应该可以解决它

显然是onTextChanged"在ktx中是doAfterTextChanged,我用的是这个:

inline fun EditText.onTextChanged(crossinline textChangeListener: (String) -> Unit) {addTextChangedListener(对象:TextWatcher {覆盖乐趣 afterTextChanged(editable: Editable) {textChangeListener(editable.toString())}覆盖乐趣 beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}覆盖 fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}})}

im trying to do login using retrofit and viewmodel

i have done successfully login with only retrofit...referred this tutorial--> https://www.youtube.com/watch?v=j0wH0m_xYLs

i havent found any tutorial related to login using viewmodel

found this stackoverflow question but it is still unanswered --> How to make retrofit API call request method post using LiveData and ViewModel

here is my call activity:--

class LoginActivity : BaseClassActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.login_activity)
    val button = findViewById<ImageView>(R.id.plusbutton)
    val forgotpassword=findViewById<TextView>(R.id.forgotpassword)
    button.setOnClickListener {
        val i = Intent(applicationContext, RegisterActivity::class.java)
        startActivity(i)
    }
    forgotpassword.setOnClickListener{
        val i = Intent(applicationContext, ForgotPassword::class.java)
        startActivity(i)
    }

    loginbtn.setOnClickListener {
        val email = loginuser.text.toString().trim()
        val password = loginpassword.text.toString().trim()

        if (email.isEmpty()) {
            Toast.makeText(
                applicationContext, "Data is missing",Toast.LENGTH_LONG
            ).show()
            loginuser.error = "Email required"
            loginuser.requestFocus()
            return@setOnClickListener
                    }


        if (password.isEmpty()) {
            loginpassword.error = "Password required"
            loginpassword.requestFocus()
            return@setOnClickListener
        }

        RetrofitClient.instance.userLogin(email, password)
            .enqueue(object : Callback<LoginResponse> {
                override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
                    Log.d("res", "" + t)


                }

                override fun onResponse(
                    call: Call<LoginResponse>,
                    response: Response<LoginResponse>
                ) {
                    var res = response

                    Log.d("response check ", "" + response.body()?.status.toString())
                    if (res.body()?.status==200) {

                        SharedPrefManager.getInstance(applicationContext)
                            .saveUser(response.body()?.data!!)

                        val intent = Intent(applicationContext, HomeActivity::class.java)
                        intent.flags =
                            Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
                        showToast(applicationContext,res.body()?.message)
                        Log.d("kjsfgxhufb",response.body()?.status.toString())
                        startActivity(intent)
                        finish()


                    }

            else
                    {
                        try {
                            val jObjError =
                                JSONObject(response.errorBody()!!.string())

                            showToast(applicationContext,jObjError.getString("user_msg"))
                        } catch (e: Exception) {
                            showToast(applicationContext,e.message)
                            Log.e("errorrr",e.message)
                        }
                    }

                }
            })

    }
}}

Following is LoginResponse:-

data class LoginResponse(val status: Int, val data: Data, val message: String, val user_msg:String)

Data class:-

data class Data(

@SerializedName("id") val id: Int,
@SerializedName("role_id") val role_id: Int,
@SerializedName("first_name") val first_name: String?,
@SerializedName("last_name") val last_name: String?,
@SerializedName("email") val email: String?,
@SerializedName("username") val username: String?,
@SerializedName("profile_pic") val profile_pic: String?,
@SerializedName("country_id") val country_id: String?,
@SerializedName("gender") val gender: String?,
@SerializedName("phone_no") val phone_no: String,
@SerializedName("dob") val dob: String?,
@SerializedName("is_active") val is_active: Boolean,
@SerializedName("created") val created: String?,
@SerializedName("modified") val modified: String?,
@SerializedName("access_token") val access_token: String?
)

really need help desparately related to viewmodel for login

thanks in advance

Errors encountered while adding epicpandaforce answer:--

in loginviewmodel:--

in loginactivity:- 1-->

2-->

3-->

解决方案

class LoginActivity : BaseClassActivity() {
    private val viewModel by viewModels<LoginViewModel>()

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

        val button = findViewById<ImageView>(R.id.plusbutton)
        val forgotpassword = findViewById<TextView>(R.id.forgotpassword)

        button.setOnClickListener {
            val i = Intent(applicationContext, RegisterActivity::class.java)
            startActivity(i)
        }

        forgotpassword.setOnClickListener {
            val i = Intent(applicationContext, ForgotPassword::class.java)
            startActivity(i)
        }

        loginuser.onTextChanged {
            viewModel.user.value = it.toString()
        }

        loginpassword.onTextChanged {
            viewModel.password.value = it.toString()
        }

        loginbtn.setOnClickListener {
            viewModel.login()
        }

        viewModel.loginResult.observe(this) { result ->
            when (result) {
                UserMissing -> {
                    Toast.makeText(
                        applicationContext, "Data is missing", Toast.LENGTH_LONG
                    ).show()
                    loginuser.error = "Email required"
                    loginuser.requestFocus()
                }
                PasswordMissing -> {
                    loginpassword.error = "Password required"
                    loginpassword.requestFocus()
                }
                NetworkFailure -> {
                }
                NetworkError -> {
                    showToast(applicationContext, result.userMessage)
                }
                Success -> {
                    val intent = Intent(applicationContext, HomeActivity::class.java)
                    intent.flags =
                        Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
                    showToast(applicationContext, res.body()?.message)
                    Log.d("kjsfgxhufb", response.body()?.status.toString())
                    startActivity(intent)
                    finish()
                }
            }.safe()
        }
    }
}

class LoginViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    sealed class LoginResult {
        object UserMissing : LoginResult(),

        object PasswordMissing : LoginResult(),

        class NetworkError(val userMessage: String) : LoginResult(),

        object NetworkFailure : LoginResult(),

        object Success : LoginResult()
    }

    val user: MutableLiveData<String> = savedStateHandle.getLiveData("user", "")
    val password: MutableLiveData<String> = savedStateHandle.getLiveData("password", "")

    private val loginResultEmitter = EventEmitter<LoginResult>()
    val loginResult: EventSource<LoginResult> = loginResultEmitter

    fun login() {
        val email = user.value!!.toString().trim()
        val password = password.value!!.toString().trim()

        if (email.isEmpty()) {
            loginResultEmitter.emit(LoginResult.UserMissing)
            return
        }


        if (password.isEmpty()) {
            loginResultEmitter.emit(LoginResult.PasswordMissing)
            return
        }

        RetrofitClient.instance.userLogin(email, password)
            .enqueue(object : Callback<LoginResponse> {
                override fun onFailure(call: Call<LoginResponse>, t: Throwable) {
                    Log.d("res", "" + t)
                    loginResultEmitter.emit(LoginResult.NetworkFailure)
                }

                override fun onResponse(
                    call: Call<LoginResponse>,
                    response: Response<LoginResponse>
                ) {
                    var res = response

                    Log.d("response check ", "" + response.body()?.status.toString())
                    if (res.body()?.status == 200) {
                        SharedPrefManager.getInstance(applicationContext).saveUser(response.body()?.data!!)
                        loginResultEmitter.emit(LoginResult.Success)
                    } else {
                        try {
                            val jObjError =
                                JSONObject(response.errorBody()!!.string())
                            loginResultEmitter.emit(LoginResult.NetworkError(jObjError.getString("user_msg")))
                        } catch (e: Exception) {
                            // showToast(applicationContext,e.message) // TODO
                            Log.e("errorrr", e.message)
                        }
                    }
                }
            })
    }
}

Using this library (that I wrote because there has not been and still isn't any other library that would solve this problem correctly without using the anti-pattern of SingleLiveEvent or the Event wrapper)

allprojects {
    repositories {
        // ...
        maven { url "https://jitpack.io" }
    }
    // ...
}

implementation 'com.github.Zhuinden:live-event:1.1.0'

EDIT: some missing blocks to actually make this compile:

fun <T> T.safe(): T = this // helper method

These dependencies in Gradle

implementation "androidx.core:core-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0"

Also add

android {
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }

  kotlinOptions {
    jvmTarget = "1.8"
  }
}

To access applicationContext in ViewModel, you'll need to use AndroidViewModel instead of ViewModel

class LoginViewModel(
    private val application: Application,
    private val savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {
    private val applicationContext = application

And that should fix it

EDIT: apparently the "onTextChanged" is doAfterTextChanged in ktx, what I use is this:

inline fun EditText.onTextChanged(crossinline textChangeListener: (String) -> Unit) {
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(editable: Editable) {
            textChangeListener(editable.toString())
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }
    })
}

这篇关于使用视图模型和改造的用户登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆