iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 30
2
Mobile Development

程式初學:Android與Kotlin系列 第 30

Day 30--Retrofit 登入練習

  • 分享至 

  • xImage
  •  

前置作業

  • build.gradle dependencies記得加入使用retrofit2
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
  • AndroidManifest.xml : 要求網路權限
<uses-permission android:name="android.permission.INTERNET" />

interface Api

登入之前須要先有帳號,所以要先註冊
提供註冊的網址是https://k88d02.ml/api/register

因爲後端的註冊請求方法是POST,發request須要帶BODY的資料
格式爲formdata如下

建立interface包含一個register funtion
還有使用@FormUrlEncoded搭配各欄位@Field的annotation

private const val BASE_URL = "https://k88d02.ml/api/"

interface ApiService {
    @Headers("Content-type: application/json","Accept: application/json")
    @POST("register")
    @FormUrlEncoded
    fun register(
        @Field("name") name: String,
        @Field("password") password: String,
        @Field("email") email: String
    ): Call<RegisterResponse>
}

object Api {

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

    val retrofitService: ApiService = retrofit.create(ApiService::class.java)
}

data class

伺服器送回的response是JSON

所以建立一個data class RegisterResponse

data class RegisterResponse(
    @SerializedName("success")
    var isSuccess: Boolean = true,
    @SerializedName("message")
    var message: String = "",
    @SerializedName("data")
    var data: Nothing? = null
)

POSTMAN

建議先測試連線是否正常,使用postman這個軟體
Send發送

可獲得response,表示連線正常

{
"success": false,
"message": "email已使用",
"data": null
}

註冊

接著就做一個登入頁面,在程式呼叫api

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        btn_register.setOnClickListener {
            hideKeyboard(textView, textView)
            Api.retrofitService
                .register(
                    ed_account.text.toString(),
                    ed_password.text.toString(),
                    ed_email.text.toString()
                )
                .enqueue(object : retrofit2.Callback<RegisterResponse> {
                    override fun onFailure(call: Call<RegisterResponse>, t: Throwable) {
                        Log.e("Failed", t.toString())
                    }

                    override fun onResponse(call: Call<RegisterResponse>, response: Response<RegisterResponse>) {

                        if (response.isSuccessful) {    //request 200,註冊成功
                            Toast.makeText(requireActivity(), response.body()?.message, Toast.LENGTH_SHORT).show()
                            Log.d("Success!", response.body().toString())
                        }else{                          //request 400,註冊失敗
                            Toast.makeText(requireActivity(), response.body()?.message, Toast.LENGTH_SHORT).show()
                            Log.d("Success!", response.body().toString())
                            Toast.makeText(requireActivity(), "註冊失敗", Toast.LENGTH_SHORT).show()
                        }
                    }

                })
        }

    }

密碼欄位可以加一個屬性,讓輸入隱藏

   android:inputType="textPassword"


可以看到第一次顯示註冊失敗,因爲密碼只輸入了4個
而伺服器要求6-12個,改爲8個後就顯示註冊成功了

logcat

D/Success!: RegisterResponse(isSuccess=true, message=register success , please login, data=null)

登入

這邊有點搞錯,原來是用email加password登入
所以我的版面欄位稍微改一下
一樣是POST,要帶的資料是formdata

所以interface加一個login funtion

interface ApiService {
    //    @Headers("Content-type: application/json","Accept: application/json")
    @POST("register")
    @FormUrlEncoded
    fun register(
        @Field("name") name: String,
        @Field("password") password: String,
        @Field("email") email: String
    ): Call<RegisterResponse>

    @POST("login")
    @FormUrlEncoded
    fun login(
        @Field("email") name: String,
        @Field("password") password: String
    ): Call<LoginResponse>
}

伺服器login獲得的response

再建立一個data class LoginResponse
裡面的rememberToken是每次登入成功時,會取得的一組token

data class LoginResponse(
    @SerializedName("data")
    val `data`: Data = Data(),
    @SerializedName("message")
    val message: String = "",
    @SerializedName("success")
    val success: Boolean = false // true
) {
    data class Data(
        @SerializedName("remember_token")
        val rememberToken: String = "", // TeR5GEi4ftp4BtKqM65Q7LYB1R0dbeY5n22ZVCulgokPigme2UFOH12VEVol
        @SerializedName("token_expire_time")
        val tokenExpireTime: String = "", // 2020/09/19 23:10:13
        @SerializedName("user_id")
        val userId: Int = 0 // 3
    )
}

先註冊一組帳號asdf@asdf.com / 密碼asdfasdf
並確認註冊成功

D/Success!: RegisterResponse(isSuccess=true, message=register success , please login, data=null)

再按下登入,可以看到顯示login的Toast有取得token

Toast.makeText(requireActivity(), response.body()?.data?.rememberToken, Toast.LENGTH_SHORT).show()

多按幾次登入,每次拿到的token都會不一樣

D/Success!: RegisterResponse(isSuccess=true, message=register success , please login, data=null)
D/Success!: LoginResponse(data=Data(rememberToken=Zs5H2xrUh7ZYIW95urGJvY2G4rozZbvtfwIqNdZ6oz1TlmLM93pyILKZUVSt, tokenExpireTime=2020/10/05 15:40:45, userId=36), message=, success=true)
D/Success!: LoginResponse(data=Data(rememberToken=yec7MPpzKUELbBOwLYge7CmDSXnrKlXUdmQGI0VEL2z4gpg7mnhMqFZzWb6t, tokenExpireTime=2020/10/05 15:40:52, userId=36), message=, success=true)
D/Success!: LoginResponse(data=Data(rememberToken=gRA8pwe33OStUjG0XbQEFQvzTtZpECW0mAh1oXmhcgOcSpo2Xuz7tojSsN4W, tokenExpireTime=2020/10/05 15:41:28, userId=36), message=, success=true)

感謝工作室與鐵人賽,雖然30天還只是一個起點
但讓我有養成學習後要記錄的習慣,感覺能夠更幫助吸收
期望能持續下去!


上一篇
Day 29--savedInstanceState狀態保存,讀取Google Sheet
系列文
程式初學:Android與Kotlin30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言