-
Notifications
You must be signed in to change notification settings - Fork 31
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주차 1단계 #60
base: jieunyume
Are you sure you want to change the base?
Changes from all commits
bc798bc
dd8ed1b
1faf7fd
e12de89
a02a8cf
b777f09
5c44b53
038b4d9
d904772
b930b26
5626965
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,4 @@ | ||
# android-map-location | ||
## step1 기능 목록 | ||
1. 저장된 검색어 목록에 기능 추가하기 | ||
- 저장된 검색어 중 하나를 선택하면 해당 검색어의 검색 결과 목록이 표시된다. | ||
2. 검색 결과 목록에 기능 추가하기 | ||
- 검색 결과 목록 중 하나의 항목을 선택하면 해당 항목의 위치를 지도에 표시한다. | ||
3. 마지막 위치 저장하기 | ||
- 앱 종료 시 마지막 위치를 SharedPreference 저장하여 다시 앱 실행 시 해당 위치로 포커스 한다. | ||
4. 에러 처리하기 | ||
- 카카오지도 onMapError() 호출 시 에러 화면을 보여준다. "지도 인증을 실패했습니다. 다시 시도해주세요. '에러이름(에러코드): 에러메세지' | ||
## step2 기능 목록 | ||
- 테스트 코드 - JUnit과 mockito를 이용하여 단위 테스트 코드를 작성한다. | ||
- data source 테스트 | ||
- local | ||
- SavedLocation 저장 테스트 | ||
- SavedLocation 삭제 테스트 | ||
- SavedLocation 조회 테스트 | ||
- 마지막 위치 저장 테스트 | ||
- UI 테스트 코드 | ||
- 검색 페이지 | ||
- 검색 결과 목록 테스트 | ||
- 검색어 저장 목록 테스트 | ||
- clearButton 테스트 | ||
- 지도 페이지 | ||
- BottomSheet 테스트 | ||
- KakaoMap Label 테스트 | ||
- 지도 에러 화면 테스트 | ||
# android-map-refactoring | ||
## 기능 목록 | ||
- 데이터베이스를 Room으로 변경한다. | ||
- Hilt를 사용하여 의존성 주입을 적용한다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package campus.tech.kakao.map | ||
|
||
import android.content.Context | ||
import androidx.room.Room | ||
import campus.tech.kakao.map.model.datasource.LastLocationlSharedPreferences | ||
import campus.tech.kakao.map.model.datasource.LocationApi | ||
import campus.tech.kakao.map.model.datasource.SavedLocationDao | ||
import campus.tech.kakao.map.model.datasource.SavedLocationDatabase | ||
import campus.tech.kakao.map.model.repository.DefaultLocationRepository | ||
import campus.tech.kakao.map.model.repository.DefaultSavedLocationRepository | ||
import campus.tech.kakao.map.model.repository.LocationRepository | ||
import campus.tech.kakao.map.model.repository.SavedLocationRepository | ||
import dagger.Binds | ||
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) | ||
class LocationModule { | ||
@Singleton | ||
@Provides | ||
fun provideLocationApi(): LocationApi { | ||
return LocationApi() | ||
} | ||
|
||
@Singleton | ||
@Provides | ||
fun provideLastLocationlSharedPreferences(): LastLocationlSharedPreferences { | ||
return LastLocationlSharedPreferences() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package campus.tech.kakao.map | ||
|
||
import campus.tech.kakao.map.model.repository.DefaultLocationRepository | ||
import campus.tech.kakao.map.model.repository.DefaultSavedLocationRepository | ||
import campus.tech.kakao.map.model.repository.LocationRepository | ||
import campus.tech.kakao.map.model.repository.SavedLocationRepository | ||
import dagger.Binds | ||
import dagger.Module | ||
import dagger.hilt.InstallIn | ||
import dagger.hilt.android.components.ViewModelComponent | ||
import dagger.hilt.components.SingletonComponent | ||
import javax.inject.Singleton | ||
|
||
@Module | ||
@InstallIn(SingletonComponent::class) | ||
// ViewModelComponent로 설정해도 될까요? Repository가 ViewModel에서 쓰이니까 ViewModelComponent를 쓰면 되겠다고 생각했는데요.. | ||
// 적절한 Component를 선택하는 기준이 뭔지 모르겠습니다! | ||
abstract class RepositoryModule { | ||
@Binds | ||
@Singleton | ||
abstract fun bindDefaultLocationRepository(impl: DefaultLocationRepository) : LocationRepository | ||
|
||
@Binds | ||
@Singleton | ||
abstract fun bindDefaultSavedLocationRepository(impl: DefaultSavedLocationRepository) : SavedLocationRepository | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package campus.tech.kakao.map | ||
|
||
import android.content.Context | ||
import androidx.room.Room | ||
import campus.tech.kakao.map.model.datasource.LastLocationlSharedPreferences | ||
import campus.tech.kakao.map.model.datasource.LocationApi | ||
import campus.tech.kakao.map.model.datasource.SavedLocationDao | ||
import campus.tech.kakao.map.model.datasource.SavedLocationDatabase | ||
import campus.tech.kakao.map.model.repository.DefaultLocationRepository | ||
import campus.tech.kakao.map.model.repository.DefaultSavedLocationRepository | ||
import campus.tech.kakao.map.model.repository.LocationRepository | ||
import campus.tech.kakao.map.model.repository.SavedLocationRepository | ||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.InstallIn | ||
import dagger.hilt.android.components.ViewModelComponent | ||
import dagger.hilt.android.qualifiers.ApplicationContext | ||
import dagger.hilt.components.SingletonComponent | ||
import javax.inject.Singleton | ||
|
||
@Module | ||
@InstallIn(SingletonComponent::class) | ||
object SavedLocationModule { | ||
@Singleton | ||
@Provides | ||
fun provideSavedLocationDatabase(@ApplicationContext context: Context): SavedLocationDatabase { | ||
return Room.databaseBuilder( | ||
context, | ||
SavedLocationDatabase::class.java, | ||
SavedLocationDatabase.DATABASE_NAME | ||
).build() | ||
} | ||
|
||
@Singleton | ||
@Provides | ||
fun provideSavedLocationDao(savedLocationDatabase: SavedLocationDatabase): SavedLocationDao { | ||
return savedLocationDatabase.savedLocationDao() | ||
} | ||
} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,11 @@ | ||
package campus.tech.kakao.map.model | ||
|
||
import androidx.room.Entity | ||
import androidx.room.PrimaryKey | ||
|
||
@Entity(tableName = "savedLocations") | ||
data class SavedLocation( | ||
@PrimaryKey(autoGenerate = true) | ||
val id: Long = 0, | ||
val title: String | ||
) |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package campus.tech.kakao.map.model.datasource | ||
|
||
import campus.tech.kakao.map.App | ||
import campus.tech.kakao.map.model.Location | ||
|
||
class LastLocationlSharedPreferences() { | ||
|
||
fun putLastLocation(location: Location) { | ||
App.sharedPreferencesManager.putString("id", location.id.toString()) | ||
App.sharedPreferencesManager.putString("longitude", location.longitude.toString()) | ||
App.sharedPreferencesManager.putString("latitude", location.latitude.toString()) | ||
App.sharedPreferencesManager.putString("title", location.title.toString()) | ||
App.sharedPreferencesManager.putString("address", location.address.toString()) | ||
App.sharedPreferencesManager.putString("category", location.category.toString()) | ||
Comment on lines
+9
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SharedPreferences 도 App 에 직접 접근하는 것이 아닌, hilt 를 통해서 주입받을 수 있도록 해주세요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 또한 DataStore 로 대체하는 작업을 해보시는 것은 어떨까요? |
||
} | ||
|
||
fun getLastLocation(): Location? { | ||
val id = App.sharedPreferencesManager.getString("id", "").toString() | ||
if(id == "") return null | ||
val title = App.sharedPreferencesManager.getString("title", "") | ||
val longitude = App.sharedPreferencesManager.getString("longitude", "").toString().toDouble() | ||
val latitude = App.sharedPreferencesManager.getString("latitude", "").toString().toDouble() | ||
val address = App.sharedPreferencesManager.getString("address", "").toString() | ||
val category = App.sharedPreferencesManager.getString("category", "").toString() | ||
return Location(id.toLong(), title, address, category, longitude, latitude) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package campus.tech.kakao.map.model.datasource | ||
|
||
import campus.tech.kakao.map.model.SearchFromKeywordResponse | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.withContext | ||
|
||
class LocationApi { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 또한 LocationApi 는 kakao api 라는 remote data source 를 사용하는 것이니, LocationRemoteDataSource 정도로 사용해보시면 어떨까요? |
||
companion object{ | ||
private const val RESULT_SIZE = 15 | ||
} | ||
|
||
private val client = RetrofitInstance.getInstance().create(KakaoAPI::class.java) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. KakaoApi 를 주입받으면 조금 더 좋은 코드가 될 수 있겠네요 :) |
||
|
||
suspend fun getLocations(keyword: String): SearchFromKeywordResponse? { | ||
return withContext(Dispatchers.IO){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dispatchers 또한 하나의 주입을 받는 대상이라고 인식하시는 것이 조금 더 좋습니다! https://developer.android.com/kotlin/coroutines/coroutines-best-practices |
||
client.searchFromKeyword(keyword, RESULT_SIZE).body() | ||
} | ||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
본인이 정하기 나름대로 사용하시면 됩니다. 만약 Repository 자체가 전역에서 사용이 될 수 있다고 한다면 SingletonComponent 를 쓰는 것이 적당하겠고, 특정 ViewModel 에서만 사용이 된다면 ViewModelComponent 를 사용하시면 됩니다.
보통 이런 부분은 소규모 과제에서 체감되기 쉽지 않아요. 조금 더 많은 기능을 구현하다보면 자연스럽게 깨닫는 부분이 오지 않을까 싶어요 :)