Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

강원대_Android_이아림_5주차과제_STEP2 #70

Open
wants to merge 13 commits into
base: arieum
Choose a base branch
from
5 changes: 2 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,11 @@ dependencies {
kapt("androidx.room:room-compiler:2.6.1")
kapt("com.google.dagger:hilt-compiler:2.51.1")
kapt("com.google.dagger:hilt-android-compiler:2.51.1")
kapt("org.xerial:sqlite-jdbc:3.41.2.2")
kapt("androidx.lifecycle:lifecycle-compiler:$lifecycle_version")

testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk-android:1.13.11")
testImplementation("io.mockk:mockk-agent:1.13.11")
testImplementation("io.mockk:mockk-android:1.13.12")
testImplementation("io.mockk:mockk-agent:1.13.12")
testImplementation("androidx.arch.core:core-testing:2.2.0")
testImplementation("org.robolectric:robolectric:4.13")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1")
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/di/DatabaseModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package campus.tech.kakao.map.data.di

import android.content.Context
import campus.tech.kakao.map.data.db.AppDatabase
import campus.tech.kakao.map.data.db.PlaceDao
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
return AppDatabase.getDatabase(context)
}

@Provides
fun providePlaceDao(database: AppDatabase): PlaceDao {
return database.placeDao()
}
}
Comment on lines +15 to +26
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

역할에 맞게 Module을 잘 구현하셨습니다! 👍
Hilt에 익숙해지시면 확실히 의존성 관리에 편하실거에요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꺅>.<😆

32 changes: 32 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package campus.tech.kakao.map.data.di

import campus.tech.kakao.map.data.remote.api.KakaoApiService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

private const val BASE_URL = "https://dapi.kakao.com/"

@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}

@Provides
@Singleton
fun provideKakaoApiService(retrofit: Retrofit): KakaoApiService {
return retrofit.create(KakaoApiService::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package campus.tech.kakao.map.data.di

import android.content.Context
import android.content.SharedPreferences
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object PreferencesModule {

@Provides
@Singleton
fun provideSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
return context.getSharedPreferences("LastLocation", Context.MODE_PRIVATE)
}
Comment on lines +18 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 방법도 좋은데 SharedPreferences를 관리하는 객체를 따로 만들어도 좋을 것 같습니다. 예를들어
KakaoMapSharedPreferences & KakaoMapSharedPreferencesImpl
등으로 Interface와 구현체를 분리해서 Module을 통해 의존성 주입해주심 더 깔끔할 것 같습니다.
해당 객체에는 Location 직렬화 및 역직렬화 하는 로직을 구현해서 사용하심 좋을 것 같습니다.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package campus.tech.kakao.map.data.di

import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import campus.tech.kakao.map.base.MyApplication
import campus.tech.kakao.map.data.db.PlaceDao
import campus.tech.kakao.map.data.remote.api.KakaoApiService
import campus.tech.kakao.map.repository.LogRepository
import campus.tech.kakao.map.repository.LogRepositoryInterface
import campus.tech.kakao.map.repository.MapRepository
import campus.tech.kakao.map.repository.MapRepositoryInterface
import campus.tech.kakao.map.repository.PlaceRepository
import campus.tech.kakao.map.repository.PlaceRepositoryInterface
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {

@Provides
@Singleton
fun provideContext(application: Application): Context {
return application.applicationContext
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hilt는 EntryPoint 등록을 통해서 각 Scope에 맞는 Context를 제공합니다.
@ApplicationContext를 활용해보세요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fun provideContext(@ApplicationContext context: Context): Context { return context }



@Provides
@Singleton
fun providePlaceRepository(sharedPreferences: SharedPreferences, kakaoApiService: KakaoApiService): PlaceRepositoryInterface {
return PlaceRepository(sharedPreferences, kakaoApiService)
}

@Provides
@Singleton
fun provideLogRepository(context: Context, placeDao: PlaceDao): LogRepositoryInterface {
return LogRepository(context.applicationContext as MyApplication, placeDao)
}

@Provides
@Singleton
fun provideMapRepository(context: Context): MapRepositoryInterface {
return MapRepository(context.applicationContext as MyApplication)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import retrofit2.http.Query

interface KakaoApiService {
@GET("v2/local/search/keyword")
fun getPlace(
suspend fun getPlace(
@Header("Authorization") apiKey: String,
@Query("query") query: String,
): Call<KakaoResponse>
): KakaoResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import javax.inject.Inject

class LogRepository @Inject constructor (private val application: MyApplication, private val placeDao: PlaceDao): LogRepositoryInterface {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Inject 를 사용해서 의존성을 생성하셨네요. 하지만, RepositoryModule에서도 LogRepository 의존성을 생성해주고 있는데 하나로 통일하시면 좋을 것 같네요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 이해가 가지않습니다...! LogRepository는 MyApplication과 PlaceDao에 대해서 의존성 주입을 받고있고 RepositoryModule에서 provideLogRepository를 작성한 이유는 LogViewModel에 의존성을 주입하기 위함이었습니다! 어떤 걸 통일해야하는지 이해가 가지 않습니다...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module을 통한 주입과 @Inject constructor를 이용한 주입 두 가지를 사용할 필요는 없다는 말씀입니다.


class LogRepository(private val application: MyApplication): LogRepositoryInterface {
private val placeDao: PlaceDao = AppDatabase.getDatabase(application).placeDao()
private var logList = mutableListOf<Place>()

override fun getAllLogs(): List<Place> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,42 @@
package campus.tech.kakao.map.repository

import android.content.ContentValues
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import campus.tech.kakao.map.BuildConfig
import campus.tech.kakao.map.R
import campus.tech.kakao.map.base.MyApplication
import campus.tech.kakao.map.data.db.entity.Place
import campus.tech.kakao.map.data.remote.api.KakaoApiService
import campus.tech.kakao.map.data.remote.model.KakaoResponse
import campus.tech.kakao.map.data.remote.api.RetrofitClient
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject

class PlaceRepository(private val application: MyApplication): PlaceRepositoryInterface {
private val sharedPreferences = application.getSharedPreferences("LastLocation", Context.MODE_PRIVATE)
class PlaceRepository @Inject constructor(
private val sharedPreferences: SharedPreferences,
private val kakaoApiService: KakaoApiService
): PlaceRepositoryInterface {

override fun searchPlaces(query: String, callback: (List<Place>) -> Unit){
override suspend fun searchPlaces(query: String): List<Place>{
val apiKey = "KakaoAK " + BuildConfig.KAKAO_REST_API_KEY
val retrofitService = RetrofitClient.retrofitService

retrofitService.getPlace(apiKey, query)
.enqueue(object : Callback<KakaoResponse> {
override fun onResponse(
call: Call<KakaoResponse>,
response: Response<KakaoResponse>
) {
if (response.isSuccessful) {
val documentList = response.body()?.documents ?: emptyList()
val placeList = documentList.map {
Place(
img = R.drawable.location,
name = it.placeName,
location = it.addressName,
category = it.categoryGroupName,
x = it.x,
y = it.y)
}
callback(placeList)
} else {
Log.d("KakaoAPI", response.errorBody()?.string().toString())
callback(emptyList())
}
}

override fun onFailure(call: Call<KakaoResponse>, t: Throwable) {
Log.d("KakaoAPI", "Failure: ${t.message}")
callback(emptyList())
}
})
return try {
val response = kakaoApiService.getPlace(apiKey, query)
val documentList = response.documents ?: emptyList()
documentList.map {
Place(
img = R.drawable.location,
name = it.placeName,
location = it.addressName,
category = it.categoryGroupName,
x = it.x,
y = it.y
)
}
} catch (e: Exception) {
Log.e("KakaoAPI", "Failure: ${e.message}")
emptyList()
}
}

override fun saveLastLocation(item: Place) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package campus.tech.kakao.map.repository
import campus.tech.kakao.map.data.db.entity.Place

interface PlaceRepositoryInterface {
fun searchPlaces(query: String, callback: (List<Place>) -> Unit)
suspend fun searchPlaces(query: String): List<Place>

fun saveLastLocation(item: Place)
}
6 changes: 2 additions & 4 deletions app/src/main/java/campus/tech/kakao/map/view/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,8 @@ class MainActivity : AppCompatActivity() {
}
}
private fun handleTextChanged(query: String){
// ViewModel에 콜백전달 -> 순서부여
placeViewModel.callResultList(query){
observePlaceListChanges()
}
placeViewModel.callResultList(query)
observePlaceListChanges()
}
private fun observePlaceListChanges(){
updatePlaceList()
Expand Down
Loading