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_주수민 2주차 과제 Step2 #34

Open
wants to merge 17 commits into
base: cleonno3o
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
# android-map-keyword

## 1단계
- [x] 기본 레이아웃 구현
- [x] 로컬 데이터베이스 구현
- [x] 검색 결과 표시 레이아웃 구현
- [x] 결과 목록 레이아웃
- [x] 결과 아이템 레이아웃

## 2단계
- [x] 검색어를 입력하면 검색 결과 목록 표시
- [x] 검색 결과 목록 스크롤 가능
- [x] 입력한 검색어 X 버튼을 통해 삭제 가능
- [x] 검색 결과에서 항목 선택 시 검색어 저장 목록에 추가
- [x] 저장된 검색어 가로 스크롤 가능
- [x] 저장된 검색어 X 버튼을 통해 삭제 가능
- [x] 저장된 검색어 DB에 저장
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/DatabaseListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package campus.tech.kakao.map

interface DatabaseListener {
fun deleteHistory(historyName: String)
fun insertHistory(historyName: String)
fun updateSearchResult()
fun updateSearchHistory()
}
49 changes: 49 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/HistoryRecyclerAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package campus.tech.kakao.map

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder

class HistoryRecyclerAdapter(
var history: List<String>,
val layoutInflater: LayoutInflater,
val databaseListener: DatabaseListener
) : RecyclerView.Adapter<HistoryRecyclerAdapter.HistoryViewHolder>() {
inner class HistoryViewHolder(itemView: View) : ViewHolder(itemView) {
val name: TextView = itemView.findViewById(R.id.history_name)
val clear: ImageButton = itemView.findViewById(R.id.history_clear)

init {
clear.setOnClickListener {
if (bindingAdapterPosition != RecyclerView.NO_POSITION) {
databaseListener.deleteHistory(name.text.toString())
}
}
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryViewHolder {
val view = layoutInflater.inflate(R.layout.item_search_history, parent, false)
return HistoryViewHolder(view)
}

override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) {
holder.name.text = history[position]
}

override fun getItemCount(): Int {
return history.size
}

fun refreshList() {
notifyDataSetChanged()
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/Location.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package campus.tech.kakao.map

data class Location(
val name: String,
val category: String,
val address: String
) {
companion object {
const val CAFE: String = "카페"
const val PHARMACY: String = "약국"
const val RESTAURANT: String = "식당"
const val NORMAL: String = "일반"
}
}
95 changes: 94 additions & 1 deletion app/src/main/java/campus/tech/kakao/map/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,104 @@
package campus.tech.kakao.map

import android.os.Bundle
import android.widget.EditText
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity(), DatabaseListener {
private lateinit var viewModel: MapViewModel
private lateinit var searchBox: EditText
private lateinit var searchHistoryView: RecyclerView
private lateinit var searchResultView: RecyclerView
private lateinit var message: TextView
private lateinit var clear: ImageButton

private lateinit var searchResultAdapter: ResultRecyclerAdapter
private lateinit var searchHistoryAdapter: HistoryRecyclerAdapter

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

viewModel = MapViewModel(this, this)
searchBox = findViewById(R.id.search_box)
searchHistoryView = findViewById(R.id.search_history)
searchResultView = findViewById(R.id.search_result)
message = findViewById(R.id.message)
clear = findViewById(R.id.clear)

searchBox.doAfterTextChanged {
it?.let {
search(it.toString(), false)
}
}

clear.setOnClickListener {
searchBox.text.clear()
}

initSearchResultView()
initSearchHistoryView()
observeData()
}

override fun deleteHistory(historyName: String) {
viewModel.deleteHistory(historyName)
}

override fun insertHistory(historyName: String) {
viewModel.insertHistory(historyName)
}

override fun updateSearchResult() {
val searchResult = viewModel.searchResult.value!!
searchResultAdapter.refreshList()

if (searchResult.isNotEmpty() && searchBox.text.isNotEmpty()) {
searchResultView.isVisible = true
message.isVisible = false
} else {
searchResultView.isVisible = false
message.isVisible = true
}
}

override fun updateSearchHistory() {
searchHistoryAdapter.refreshList()
}

private fun search(locName: String, isExactMatch: Boolean) {
viewModel.searchLocation(locName, isExactMatch)
}

private fun initSearchResultView() {
searchResultAdapter =
ResultRecyclerAdapter(viewModel.searchResult.value!!, layoutInflater, this)
searchResultView.adapter = searchResultAdapter
searchResultView.layoutManager =
LinearLayoutManager(this@MainActivity, LinearLayoutManager.VERTICAL, false)
}

private fun initSearchHistoryView() {
searchHistoryAdapter =
HistoryRecyclerAdapter(viewModel.getAllHistory(), layoutInflater, this)
searchHistoryView.adapter = searchHistoryAdapter
searchHistoryView.layoutManager =
LinearLayoutManager(this@MainActivity, LinearLayoutManager.HORIZONTAL, false)
}

private fun observeData() {
viewModel.searchHistory.observe(this, Observer {
searchHistoryAdapter.history = it
})
viewModel.searchResult.observe(this, Observer {
searchResultAdapter.searchResult = it
})
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MapContract.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package campus.tech.kakao.map

import android.provider.BaseColumns

object MapContract {
object MapEntry : BaseColumns {
const val TABLE_NAME = "map"
const val TABLE_NAME_HISTORY = "history"
const val COLUMN_NAME_NAME = "name"
const val COLUMN_NAME_CATEGORY = "category"
const val COLUMN_NAME_ADDRESS = "address"
}
}
61 changes: 61 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/MapDbHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package campus.tech.kakao.map

import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.provider.BaseColumns

class MapDbHelper(mContext: Context) :
SQLiteOpenHelper(mContext, DATABASE_NAME, null, DATABASE_VERSION) {
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(SQL_CREATE_ENTRIES)
db?.execSQL(SQL_CREATE_ENTRIES_HISTORY)
initializeDb(db)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db?.execSQL(SQL_DELETE_ENTRIES)
Copy link

Choose a reason for hiding this comment

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

db 버전이 업그레이드될때 실행되는 마이그레이션 작업인데
지금은 모든 데이터를 지우고 새로 설정 해주시고 계시네요 ㅎㅎ
지금은 실 서비스가 아니니까 상관 없는데
실제 서비스를 할땐 이런 작업을 유의해야합니다.
앱 업데이트를 했는데 내가 저장해둔 데이터가 날아가면... 무수히 많은 문의를 받을수도 있거든요

Copy link
Author

Choose a reason for hiding this comment

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

이번 과제에서 실제로 upgrade하는 상황이 발생하지 않아 다 지워버리고 새로 생성한다고 구현했던 것 같습니다! 하지만 실제 서비스에서는 발생하면 정말 아찔할 것 같습니다.. 앞으로 실제 서비스여도 괜찮을지 고민해보며 구현하겠습니다!

db?.execSQL(SQL_DELETE_ENTRIES_HISTORY)
onCreate(db)
}

private fun initializeDb(db: SQLiteDatabase?) {
for (idx in 1..10) {
val exampleCafeValue = ContentValues()
exampleCafeValue.put(MapContract.MapEntry.COLUMN_NAME_NAME, "카페$idx")
exampleCafeValue.put(MapContract.MapEntry.COLUMN_NAME_CATEGORY, Location.CAFE)
exampleCafeValue.put(MapContract.MapEntry.COLUMN_NAME_ADDRESS, "서울 성동구 성수동 $idx")
db?.insert(MapContract.MapEntry.TABLE_NAME, null, exampleCafeValue)

val examplePharValue = ContentValues()
examplePharValue.put(MapContract.MapEntry.COLUMN_NAME_NAME, "약국$idx")
examplePharValue.put(MapContract.MapEntry.COLUMN_NAME_CATEGORY, Location.PHARMACY)
examplePharValue.put(MapContract.MapEntry.COLUMN_NAME_ADDRESS, "서울 성동구 성수동 $idx")
db?.insert(MapContract.MapEntry.TABLE_NAME, null, examplePharValue)
}
}

companion object {
const val DATABASE_NAME = "map.db"
const val DATABASE_VERSION = 1

private const val SQL_CREATE_ENTRIES =
"CREATE TABLE ${MapContract.MapEntry.TABLE_NAME} (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
"${MapContract.MapEntry.COLUMN_NAME_NAME} TEXT," +
"${MapContract.MapEntry.COLUMN_NAME_CATEGORY} TEXT," +
"${MapContract.MapEntry.COLUMN_NAME_ADDRESS} TEXT" +
");"
private const val SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS ${MapContract.MapEntry.TABLE_NAME}"

private const val SQL_CREATE_ENTRIES_HISTORY =
"CREATE TABLE ${MapContract.MapEntry.TABLE_NAME_HISTORY} (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
"${MapContract.MapEntry.COLUMN_NAME_NAME} TEXT" +
");"
private const val SQL_DELETE_ENTRIES_HISTORY =
"DROP TABLE IF EXISTS ${MapContract.MapEntry.TABLE_NAME_HISTORY}"
}
}
Loading