안드로이드

레트로핏의 동기적 실행

2024. 1. 14. 22:15
글 목차


728x90

시연영상

https://www.youtube.com/watch?v=PTlpwTyFiak&feature=youtu.be

t

 

필요한 이유

현재 만들고 있는 안드로이드 앱 프로젝트에서 로그인 Api가 요청에 대한 응답을 만들어 내는데 긴 시간이 걸린다.

그래서 기존에 쓰던 방법으로 레트로핏을 사용했더니 응답을 받기전에 다음 코드를 실행해 버리는 문제가 발생했다.

 

따라서 응답이 올때까지 기다리게 하고 다음 코드를 실행 할 수 있도록 수정해야 할 필요성이 있다.

그래서 예시 프로젝트를 만들어 봤다.

 

시연영상을 만들기 위한 코드를 살펴보자

 

 

소스코드

https://github.com/okanekudasai/retrofit_sync

 

GitHub - okanekudasai/retrofit_sync

Contribute to okanekudasai/retrofit_sync development by creating an account on GitHub.

github.com

 

 

만든 방법

자잘한 설정들

1. manifest에 추가할 것

<uses-permission android:name="android.permission.INTERNET" />

http 요청을 하기 위한것

android:usesCleartextTraffic="true"

https로 요청을 안보내도 오류가 안보내게 하는 코드

 

Manifast.xml의 전체코드는 아래와 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Example_response"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

2. build.gradle에 설정할 것

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    namespace 'com.example.example_response'
    compileSdk 33

	-- 뷰 바인딩을 위한것 --
    viewBinding {
        enabled = true
    }

    defaultConfig {
        applicationId "com.example.example_response"
        minSdk 24
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.8.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

    -- 레트로핏과 코루틴을 사용하기 위한 것 --
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.5.2"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
}

 

 

MainActivity

1. api 인스턴스를 만들고 GlobalScope를 관리해 주자

package com.example.example_response

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.example_response.databinding.ActivityMainBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.scalars.ScalarsConverterFactory
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
import java.util.concurrent.TimeUnit

// Api를 만들기 위한 interface
interface Api {
    @GET("long_response_api/{time}")
    suspend fun waitResponse(@Path("time") time: String): Response<String>
}

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        val okHttpClient = OkHttpClient.Builder()
            .readTimeout(60, TimeUnit.SECONDS) // 읽기 Timeout 설정 (초 단위)
            .connectTimeout(60, TimeUnit.SECONDS) // 연결 Timeout 설정 (초 단위)
            .build()

        val api: Api = Retrofit.Builder()
            .baseUrl("http://10.0.2.2:8080/")
            .addConverterFactory(ScalarsConverterFactory.create())
            .client(okHttpClient)
            .build()
            .create(Api::class.java)

        binding.button.setOnClickListener {
            Log.d("Okane", "버튼이 눌림")
            
            // 이 스코프 안에 있는 것은 하나의 쓰레드안에서 수행되기 때문에 코드가 순차적으로 수행된다.
            GlobalScope.launch(Dispatchers.IO) {
                var t = binding.editText.text.toString()

                Log.d("Okane", t)
                val response = api.waitResponse(t)
//                if(response.isSuccessful) {
//                    Log.d("Okane", response.body()!!)
//                }
                Log.d("Okane", "여긴 response를 받아오고 수행됨")
            }
            Log.d("Okane", "여긴 reponse를 받기전에 수행됨")
        }
    }


}

GlobalScope.launch(Dispatchers.IO)은 Kotlin에서 kotlinx.coroutines 라이브러리를 사용하여 글로벌 스코프에서 IO 디스패처를 사용하여 코루틴을 시작하는 코드다

  • GlobalScope: 글로벌 스코프는 애플리케이션 수명 주기와 관련이 있으며 애플리케이션이 실행되는 동안 계속해서 코루틴을 관리하는 스코프다. 글로벌 스코프에서 실행되는 코루틴은 애플리케이션 전체에서 접근 가능
  • launch(Dispatchers.IO): launch 함수는 비동기적으로 코드 블록을 실행하는 새로운 코루틴을 시작한다. Dispatchers.IO는 입출력 작업에 최적화된 디스패처로, 파일 입출력, 네트워크 호출과 같은 블록되는 작업들을 효과적으로 처리할 수 있도록 최적화되어 있다.

따라서, GlobalScope.launch(Dispatchers.IO)은 글로벌 스코프에서 IO 디스패처를 사용하여 비동기적으로 코드를 실행하는 새로운 코루틴을 시작하는 것을 의미한다. 이를 통해 입출력 작업을 블록하지 않고 비동기적으로 처리할 수 있다

728x90
레트로핏의 동기적 실행