MapActivity.kt
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
AndroidManifest.xml
<!-- 인터넷 사용 권한 -->
<uses-permission android:name="android.permission.INTERNET" />
AndroidManifest.xml
<!-- 사용자 위치 권한 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
MapActivity.kt
override fun onMapReady(map: NaverMap){
// 사용자에게 실제로 권한 요청
ActivityCompat.requestPermissions(
this, PERMISSION,
LOCATION_PERMISSION_REQUEST_CODE
)
}
private var PERMISSION = arrayOf(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION
)
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1000
}
MapAcitivty.kt
private lateinit var locationSource: FusedLocationSource
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// FusedLocationSource : 위치 정보를 관리하고 요청하는데 사용되는 클래스.
locationSource = FusedLocationSource(this, LOCATION_PERMISSION_REQUEST_CODE)
getMarkers()
}
override fun onMapReady(map: NaverMap){
binding.currentLocationButton.map = naverMap
naverMap?.locationSource = locationSource
val uiSetting = naverMap?.uiSettings
uiSetting?.isLocationButtonEnabled = false
naverMap?.maxZoom = 18.0
naverMap?.minZoom = 10.0
}
override fun onMapReady(map: NaverMap){
naverMap?.setOnMapClickListener{ _, coord ->
blueMarker?.map = null
val bMarker = Marker()
bMarker.position = coord
bMarker.icon = MarkerIcons.BLUE
bMarker.map = naverMap
blueMarker = bMarker
getMarkers()
showSaveDialog(coord)
}
}
private fun showSaveDialog(coord: LatLng) {
val alertDialog = AlertDialog.Builder(this)
.setMessage("장소를 저장하겠습니까?")
.setPositiveButton("예") { dialogInterface: DialogInterface, i: Int ->
val intent = Intent(this, SaveActivity::class.java)
intent.putExtra("latitude", coord.latitude)
intent.putExtra("longitude", coord.longitude)
startActivity(intent)
}
.setNegativeButton("아니오", null)
.create()
alertDialog.show()
}
private fun getMarkers(){
CoroutineScope(Dispatchers.IO).launch {
withContext(Dispatchers.Main){
val markerList = database.dao().getAll()
redMarker?.map = null
for (marker in markerList){
val latlng = LatLng(marker.lat, marker.lng)
val mk = Marker()
mk.position = latlng
mk.iconTintColor = Color.RED
mk.map = naverMap
mk.onClickListener = this@MapActivity
mk.tag = marker
redMarker = mk
}
}
}
}
private val markerClickListener = object : Overlay.OnClickListener{
override fun onClick(overlay: Overlay): Boolean {
if (overlay is Marker){
if (overlay == blueMarker){
showSaveDialog(overlay.position)
return true
}
val model = overlay.tag as? MarkerEntity
model ?: return false
infoWindow.adapter = object : InfoWindow.DefaultTextAdapter(applicationContext){
override fun getText(p0: InfoWindow): CharSequence {
return model.title
}
}
infoWindow.open(overlay)
return true
}
return false
}
}
override fun onClick(p0: Overlay): Boolean {
return markerClickListener.onClick(p0)
}
activity_save.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#009900"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
tools:ignore="MissingConstraints" />
<EditText
android:id="@+id/titleEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="20dp"
android:hint="제목을 입력하세요!"/>
<EditText
android:id="@+id/contentEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/titleEditText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="20dp"
android:hint="내용을 입력하세요!"/>
<Button
android:id="@+id/saveButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="저장하기!"
android:textStyle="bold"
android:textSize="20dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
SaveActivity.kt
class SaveActivity : AppCompatActivity() {
private lateinit var binding: ActivitySaveBinding
private var latitude: Double = 0.0
private var longitude: Double = 0.0
private lateinit var database: MyDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySaveBinding.inflate(layoutInflater)
setContentView(binding.root)
database = MyDatabase.getDatabase(this)
latitude = intent.getDoubleExtra("latitude", 0.0)
longitude = intent.getDoubleExtra("longitude", 0.0)
// 저장 버튼 클릭 시 데이터베이스에 저장
binding.saveButton.setOnClickListener {
val markerTitle = binding.titleEditText.text.toString()
val markerContent = binding.contentEditText.text.toString()
CoroutineScope(Dispatchers.IO).launch {
database.dao().insert(MarkerEntity(
title = markerTitle,
content = markerContent,
lat = latitude,
lng = longitude
))
}
finish()
}
}
}
MarkerDao.kt
@Dao
interface MarkerDao {
@Insert
suspend fun insert(entity: MarkerEntity)
@Query("SELECT * FROM markerentity")
suspend fun getAll(): List<MarkerEntity>
@Query("DELETE FROM markerentity")
suspend fun deleteAll()
}
MarkerEntity.kt
@Entity
data class MarkerEntity (
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val title: String,
val content: String,
val lat: Double,
val lng: Double
)
MyDatabase.kt
@Database(entities = [MarkerEntity::class], version = 1)
abstract class MyDatabase : RoomDatabase(){
abstract fun dao(): MarkerDao
companion object{
@Volatile
private var INSTANCE: MyDatabase? = null
fun getDatabase(context: Context): MyDatabase{
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
MyDatabase::class.java,
"marker-database"
).build()
INSTANCE = instance
instance
}
}
}
}
antivity_data.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/dataText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="30dp"/>
<Button
android:id="@+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="메인으로"
android:layout_marginBottom="20dp"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/deleteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_margin="20dp"
android:src="@drawable/baseline_delete_24"
android:contentDescription="@string/delete" />
</androidx.constraintlayout.widget.ConstraintLayout>
DataActivity.kt
class DataActivity: AppCompatActivity() {
private lateinit var binding: ActivityDataBinding
private lateinit var database: MyDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDataBinding.inflate(layoutInflater)
setContentView(binding.root)
database = MyDatabase.getDatabase(this)
getMarkers()
binding.deleteButton.setOnClickListener {
deleteMarkers()
}
binding.backButton.setOnClickListener {
finish()
}
}
private fun getMarkers() {
CoroutineScope(Dispatchers.IO).launch {
val markers = database.dao().getAll().joinToString("\n\n")
binding.dataText.text = markers
}
}
private fun deleteMarkers(){
CoroutineScope(Dispatchers.IO).launch {
database.dao().deleteAll()
}
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?){
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.mapButton.setOnClickListener {
val intent = Intent(this, MapActivity::class.java)
startActivity(intent)
}
binding.dataButton.setOnClickListener {
val intent = Intent(this, DataActivity::class.java)
startActivity(intent)
}
}
}
antivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<Button
android:id="@+id/mapButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/dataButton"
app:layout_constraintVertical_chainStyle="packed"
android:text="지도 이동"/>
<Button
android:id="@+id/dataButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/mapButton"
android:text="저장 확인"/>
</androidx.constraintlayout.widget.ConstraintLayout>