til

DAY 6

paulaner80 2021. 12. 24. 11:47
반응형

Retrofit을 사용한 통신

 

1. 의존성 추가
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation "com.squareup.okhttp3:logging-interceptor:4.8.1"

    참고로 의존성 버전확인은 Project Structure > dependencies에서 확인할 수 있습니다.

    의존성 추가 한후 sync now 해줍니다.

2. 인터넷 사용 허용
<uses-permission android:name="android.permission.INTERNET"/


 3가지 구성요소
Interface
Retrofit.Builder
DTO (POJO)

 

4.  전체소스 소스


IRetrofit.kt  : Interface에 해당

package com.exmaple.retrofit_test

import com.google.gson.JsonElement
import retrofit2.Call
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST

interface IRetrofit {
    @FormUrlEncoded
    @POST("/login")
    fun loginRequest(
            @Field("username") username:String,
            @Field("password") password:String
    ): Call<JsonElement>
}

 

RetrofitClient.kt  Retrofit.Builder에 해당

package com.exmaple.retrofit_test

import android.util.Log
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

object RetrofitClient {

    private var retrofitClient:Retrofit? = null
    private val TAG = "로그"

    fun getClient(baseUrl:String) : Retrofit?{
        if(retrofitClient == null){
            val client = OkHttpClient.Builder()

            val loggingInterceptor =HttpLoggingInterceptor(object:HttpLoggingInterceptor.Logger{
                override fun log(message: String) {
                    Log.d(TAG,"RetrofitClient - log : ${message}")
                }
            })

            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
            client.addInterceptor(loggingInterceptor)

            client.connectTimeout(10, TimeUnit.SECONDS)
            client.readTimeout(10, TimeUnit.SECONDS)
            client.writeTimeout(10, TimeUnit.SECONDS)
            client.retryOnConnectionFailure(true)

            retrofitClient =Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client.build())
                .build()
        }

        return retrofitClient;


    }

}

 

RetrofitManager.kt

package com.exmaple.retrofit_test

import android.util.Log
import com.google.gson.JsonElement
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class RetrofitManager {
    private val baseUrl = "http://192.168.21.126:5000"
    private val TAG = "로그"

    companion object{
        val instance = RetrofitManager()
    }
    private val iRetrofit: IRetrofit? = RetrofitClient.getClient(baseUrl)?.create(IRetrofit::class.java)

    fun loging(username:String, password:String, completion:(LoginResponse, String)->Unit){
        var call = iRetrofit?.loginRequest(username, password) ?:return

        call.enqueue(object: Callback<JsonElement> {
            override fun onResponse(call: Call<JsonElement>, response: Response<JsonElement>) {
                Log.d(TAG, "RetrofitManager - onResponse body : ${response.body()}")
                Log.d(TAG, "RetrofitManager - onResponse code : ${response.code()}")
                if(response.code() == 200){
                    completion(LoginResponse.OK, response.body().toString())
                }else{
                    completion(LoginResponse.FAIL, response.body().toString())
                }
            }

            override fun onFailure(call: Call<JsonElement>, t: Throwable) {
                Log.d(TAG, "RetrofitManager - onFailure")
                completion(LoginResponse.FAIL, t.toString())
            }
        })
    }
}

 

MainActivity.kt

package com.exmaple.retrofit_test

import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import android.os.Bundle
import android.os.PersistableBundle
import android.util.Log
import androidx.appcompat.app.AlertDialog
import com.exmaple.retrofit_test.databinding.ActivityMainBinding

class MainActivity:AppCompatActivity(){

    private lateinit var binding:ActivityMainBinding
    private val TAG = "로그"

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

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.user = User("pepper","123123")

        binding.loginButton.setOnClickListener{
            Log.d(TAG,"MainActivity login button click");
            var username = binding.usernameInput.text.toString()
            var password = binding.passwordInput.text.toString()

            loginRequest(username, password)
        }
    }

    private fun loginRequest(username: String, password: String) {
        var dialogBuilder =AlertDialog.Builder(this@MainActivity)
        if(username.isEmpty() || password.isEmpty()){
            dialogBuilder.setTitle("알림")
            dialogBuilder.setMessage("빈 칸을 전부 채워주세요")
            dialogBuilder.setPositiveButton("확인",null)
            dialogBuilder.show()
        }else{
            RetrofitManager.instance.loging(
                username = username,
                password = password,
                completion ={loginResponse, response ->
                    when(loginResponse){
                        LoginResponse.FAIL->{
                            dialogBuilder.setTitle("알림")
                            dialogBuilder.setMessage("로그인 실패")
                            dialogBuilder.setPositiveButton("확인",null)
                            dialogBuilder.show()
                        }
                        LoginResponse.OK->{
                            dialogBuilder.setTitle("알림")
                            dialogBuilder.setMessage("로그인 성공")
                            dialogBuilder.setPositiveButton("확인",null)
                            dialogBuilder.show()
                        }
                    }
                }
            )
        }

    }
}

data class User(val name:String, val pass:String);

 

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <import type="android.view.View"/>
        <variable
            name="user"
            type="com.exmaple.retrofit_test.User" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout 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"
        tools:context=".MainActivity">

        <EditText
            android:id="@+id/username_input"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="200dp"
            android:text="@{user.name}"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <EditText
            android:id="@+id/password_input"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="@{user.pass}"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/username_input" />

        <Button
            android:id="@+id/login_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="로그인"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/password_input" />

        <Button
            android:id="@+id/test_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="테스트"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/login_button" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>



***

val name: String = nm ?: "" //nm라는 변수가null 이면 name에 ""가 들어감

object

싱글턴 클래스로 만들 때
익명 클래스 객체를 생성할 때

*** 참고 Retrofit API Declaration

API Declaration
Annotations on the interface methods and its parameters indicate how a request will be handled.

REQUEST METHOD
Every method must have an HTTP annotation that provides the request method and relative URL. There are eight built-in annotations: HTTP, GET, POST, PUT, PATCH, DELETE, OPTIONS and HEAD. The relative URL of the resource is specified in the annotation.

@GET("users/list")
You can also specify query parameters in the URL.

@GET("users/list?sort=desc")
URL MANIPULATION
A request URL can be updated dynamically using replacement blocks and parameters on the method. A replacement block is an alphanumeric string surrounded by { and }. A corresponding parameter must be annotated with @Path using the same string.

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
Query parameters can also be added.

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
For complex query parameter combinations a Map can be used.

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
REQUEST BODY
An object can be specified for use as an HTTP request body with the @Body annotation.

@POST("users/new")
Call<User> createUser(@Body User user);
The object will also be converted using a converter specified on the Retrofit instance. If no converter is added, only RequestBody can be used.

FORM ENCODED AND MULTIPART
Methods can also be declared to send form-encoded and multipart data.

Form-encoded data is sent when @FormUrlEncoded is present on the method. Each key-value pair is annotated with @Field containing the name and the object providing the value.

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
Multipart requests are used when @Multipart is present on the method. Parts are declared using the @Part annotation.

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
Multipart parts use one of Retrofit's converters or they can implement RequestBody to handle their own serialization.

HEADER MANIPULATION
You can set static headers for a method using the @Headers annotation.

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
Note that headers do not overwrite each other. All headers with the same name will be included in the request.

A request Header can be updated dynamically using the @Header annotation. A corresponding parameter must be provided to the @Header. If the value is null, the header will be omitted. Otherwise, toString will be called on the value, and the result used.

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
Similar to query parameters, for complex header combinations, a Map can be used.

@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
He

'til' 카테고리의 다른 글

day10  (0) 2021.12.28
day 9  (0) 2021.12.27
DAY 5  (0) 2021.12.23
Day4  (0) 2021.12.22
day2  (0) 2021.12.20