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 #61

Open
wants to merge 18 commits into
base: ddangcong80
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 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

### Week2-Step1 로컬 데이터
- 검색어 입력 및 검색 결과를 표시할 기본 레이아웃을 구현한다.
- 검색에 사용될 데이터를 로컬 데이터베이스에 생성한다.
- 검색 데이터의 저장은 SQLite를 사용한다.
- 가능한 MVVM 아키텍처 패턴을 적용하도록 한다.

### Week2-Step2 검색
- 검색어를 입력하면 검색 결과 목록이 표시된다.
- 검색 결과 목록은 세로 스크롤이 된다.
- 입력한 검색어는 X를 눌러서 삭제할 수 있다.
- 검색 결과 목록에서 하나의 항목을 선택할 수 있다.
- 선택된 항목은 검색어 저장 목록에 추가된다.
- 저장된 검색어 목록은 가로 스크롤이 된다.
- 저장된 검색어는 X를 눌러서 삭제할 수 있다.
- 저장된 검색어는 앱을 재실행하여도 유지된다.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
android:theme="@style/Theme.Map"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:name=".view.SearchActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
11 changes: 0 additions & 11 deletions app/src/main/java/campus/tech/kakao/map/MainActivity.kt

This file was deleted.

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

data class Place(
val name: String,
val address: String,
val category: String
)

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

import android.provider.BaseColumns

object PlaceContract {
object PlaceEntry : BaseColumns {
const val TABLE_NAME = "place"
const val COLUMN_PLACE_NAME = "place"
const val COLUMN_PLACE_ADDRESS = "address"
const val COLUMN_PLACE_CATEGORY = "category"
const val CREATE_QUERY = "CREATE TABLE IF NOT EXISTS $TABLE_NAME (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY," +
"$COLUMN_PLACE_NAME varchar(30)," +
"$COLUMN_PLACE_ADDRESS varchar(255)," +
"$COLUMN_PLACE_CATEGORY varchar(30))"
const val DROP_QUERY = "DROP TABLE IF EXISTS $TABLE_NAME"
}

object SavePlaceEntry : BaseColumns {
const val TABLE_NAME = "savePlace"
const val COLUMN_PLACE_NAME = "savePlaceName"
private const val COLUMN_TIMESTAMP = "timestamp"
const val CREATE_QUERY = "CREATE TABLE IF NOT EXISTS $TABLE_NAME (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY," +
"$COLUMN_PLACE_NAME varchar(30)," +
"$COLUMN_TIMESTAMP DATETIME DEFAULT CURRENT_TIMESTAMP)"
const val DROP_QUERY = "DROP TABLE IF EXISTS $TABLE_NAME"
}
}
19 changes: 19 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/model/PlaceDBHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package campus.tech.kakao.map.model

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class PlaceDBHelper(context: Context) : SQLiteOpenHelper(context, "placedb", null, 1) {
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(PlaceContract.PlaceEntry.CREATE_QUERY)
db?.execSQL(PlaceContract.SavePlaceEntry.CREATE_QUERY)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db?.execSQL(PlaceContract.PlaceEntry.DROP_QUERY)
db?.execSQL(PlaceContract.SavePlaceEntry.DROP_QUERY)
onCreate(db)
}

}
5 changes: 5 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/model/SavePlace.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package campus.tech.kakao.map.model

data class SavePlace (
val savePlace: String,
)
172 changes: 172 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/repository/SearchRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package campus.tech.kakao.map.repository

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.util.Log
import campus.tech.kakao.map.model.Place
import campus.tech.kakao.map.model.PlaceContract
import campus.tech.kakao.map.model.PlaceDBHelper
import campus.tech.kakao.map.model.SavePlace

class SearchRepository(context: Context) {
private val dbHelper = PlaceDBHelper(context)

fun isDataExists(category: String): Boolean {

Choose a reason for hiding this comment

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

이 함수는 내부에서만 사용한는 것으로 보이는데요 private을 붙여주면 좋습니다.
나중에 협업할 때 해당 함수가 외부에서 사용될 수 있다고 판단되어 무분별한 사용이 일어날 수 있습니다.

val db: SQLiteDatabase = dbHelper.readableDatabase

Choose a reason for hiding this comment

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

DB관련 로직 + 쿼리는 Helper에 두고 해당 함수를 불러서 사용하는 식으로 하면 더 좋을 것 같습니다

val cursor: Cursor = db.query(
PlaceContract.PlaceEntry.TABLE_NAME,
arrayOf(PlaceContract.PlaceEntry.COLUMN_PLACE_CATEGORY),
"${PlaceContract.PlaceEntry.COLUMN_PLACE_CATEGORY} = ?",
arrayOf(category),
null,
null,
null
)
val exists = cursor.count > 0
cursor.close()
db.close()

Choose a reason for hiding this comment

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

여기서는 close를 잘 해주셨는데요 다른곳에서도 꼭 해주시기 바랍니다
메모리 릭의 원인이 될 수 있습니다.

return exists
}

fun insertPlaceDummyData(name: String, address: String, category: String) {
if (isDataExists(category)) {
Log.d("ddangcong80", "Category $category already exists.")
return
}

val db: SQLiteDatabase = dbHelper.writableDatabase
val values = ContentValues()
for (i in 1..15) {
values.put(PlaceContract.PlaceEntry.COLUMN_PLACE_NAME, name + i)
values.put(PlaceContract.PlaceEntry.COLUMN_PLACE_ADDRESS, address + i)
values.put(PlaceContract.PlaceEntry.COLUMN_PLACE_CATEGORY, category)
db.insert(PlaceContract.PlaceEntry.TABLE_NAME, null, values)
}
}

fun getSearchPlaces(placeCategory: String): MutableList<Place> {
val db: SQLiteDatabase = dbHelper.readableDatabase
val places = mutableListOf<Place>()
var cursor: Cursor? = null
try {
val selection = "${PlaceContract.PlaceEntry.COLUMN_PLACE_CATEGORY} LIKE ?"
val selectionArgs = arrayOf("$placeCategory%")

cursor = db.query(
PlaceContract.PlaceEntry.TABLE_NAME,
null,
selection,
selectionArgs,
null,
null,
null
)

if (cursor != null) {
while (cursor.moveToNext()) {
val name =
cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_PLACE_NAME))
val address =
cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_PLACE_ADDRESS))
val category =
cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.PlaceEntry.COLUMN_PLACE_CATEGORY))

places.add(Place(name, address, category))
}
}
} catch (e: Exception) {
Log.e("ddangcong80", "Error", e)
} finally {
cursor?.close()
db.close()
}

return places
}


fun savePlaces(placeName: String) {
val db: SQLiteDatabase = dbHelper.writableDatabase
val values = ContentValues()
values.put(PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME, placeName)

val cursor = db.query(
PlaceContract.SavePlaceEntry.TABLE_NAME,
arrayOf(PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME),
"${PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME} = ?",
arrayOf(placeName),
null,
null,
null
)

if (cursor.moveToFirst()) {
db.delete(
PlaceContract.SavePlaceEntry.TABLE_NAME,
"${PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME} = ?",
arrayOf(placeName)
)
}
cursor.close()

db.insert(PlaceContract.SavePlaceEntry.TABLE_NAME, null, values)
}

fun showSavePlace(): MutableList<SavePlace> {
val db: SQLiteDatabase = dbHelper.readableDatabase
val savePlaces = mutableListOf<SavePlace>()
var cursor: Cursor? = null
try {
cursor = db.query(
PlaceContract.SavePlaceEntry.TABLE_NAME,
null,
null,
null,
null,
null,
null
)

if (cursor != null) {
while (cursor.moveToNext()) {
val name =
cursor.getString(cursor.getColumnIndexOrThrow(PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME))

savePlaces.add(SavePlace(name))
}
}
} catch (e: Exception) {
Log.e("ddangcong80", "Error", e)
} finally {
cursor?.close()
db.close()
}

return savePlaces
}

fun deleteSavedPlace(savedPlaceName: String) {
val db: SQLiteDatabase = dbHelper.writableDatabase

val cursor = db.query(
PlaceContract.SavePlaceEntry.TABLE_NAME,
arrayOf(PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME),
"${PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME} = ?",
arrayOf(savedPlaceName),
null,
null,
null
)

if (cursor.moveToFirst()) {
db.delete(
PlaceContract.SavePlaceEntry.TABLE_NAME,
"${PlaceContract.SavePlaceEntry.COLUMN_PLACE_NAME} = ?",
arrayOf(savedPlaceName)
)
}
cursor.close()
}
}
48 changes: 48 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/view/SavePlaceAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package campus.tech.kakao.map.view

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import campus.tech.kakao.map.R
import campus.tech.kakao.map.model.SavePlace

class SavePlaceAdapter(
private val savePlaces: List<SavePlace>,
private val onItemClickListener: (SavePlace) -> Unit
) : RecyclerView.Adapter<SavePlaceAdapter.SavePlaceViewHolder>() {
class SavePlaceViewHolder(
itemView: View,
private val onItemClickListener: (SavePlace) -> Unit
) : RecyclerView.ViewHolder(itemView) {
private val savePlaceTextView: TextView = itemView.findViewById(R.id.savePlace)
private val savePlaceDeleteBtn: ImageView = itemView.findViewById(R.id.saveCancelBtn)

fun bind(savePlace: SavePlace) {
savePlaceTextView.text = savePlace.savePlace
savePlaceDeleteBtn.setOnClickListener {
onItemClickListener(savePlace)
}
}
}

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): SavePlaceViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.saveplace_item, parent, false)
return SavePlaceViewHolder(view, onItemClickListener)
}

override fun onBindViewHolder(holder: SavePlaceViewHolder, position: Int) {
val savePlace = savePlaces[position]
holder.bind(savePlace)
}

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