비교적 작은 키-값 컬렉션을 저장하려면 SharedPreferences API를 사용합니다.
키-값 쌍 데이터를 파일에 저장하고 이를 읽고 쓰는 간단한 방법을 제공합니다.
키-값 쌍을 작성하려면
val sharedPref = getSharedPreferences("com.seo.loginapp.SHARED_PREF_File", Context.MODE_PRIVATE)
com.seo.loginapp.SHARED_PREF_File : 공유 환경 설정 파일의 이름을 지정할 때 앱에서 고유하게 식별할 수 있는 이름을 사용해야 합니다. 이를 수행하는 쉬운 방법은 파일 이름에 애플리케이션 ID를 접두사로 추가하는 것입니다.
Context.MODE_PRIVATE : API 레벨 17부터 MODE_PRIVATE만 지원
val editor = sharedPref.edit()
val usernameInput = findViewById<EditText>(R.id.Username)
val passwordInput = findViewById<EditText>(R.id.Password)
val buttonInput = findViewById<Button>(R.id.button)
editor.apply()
Room은 SQLite에 대한 추상화 계층을 제공하여 SQLite의 모든 기능을 활용하면서 유창한 데이터베이스 액세스를 허용합니다.
Google은 SQLite 대신 Room 사용을 권장합니다.
소프트웨어 클래스와 데이터베이스 간의 연결.
Room을 사용하려면 앱의 build.gradle에 의존성을 추가해야 한다.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.seo.database"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
def roomVersion = "2.3.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
@Entity
data class User(
@PrimaryKey val uid: Int,
val firstName: String?,
val lastName: String?
)
@Entity : 하나의 데이터베이스 구조를 결정한다
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<User>
@Query("SELECT * FROM users WHERE uid IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
@Query("SELECT * FROM users WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
fun findByName(first: String, last: String): User
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(users: User)
}
@DAO : 데이터베이스에 접근하는 데 사용되는 방법
@Insert : Room은 단일 트랜잭션의 모든 매개변수를 데이터베이스에 삽입하는 구현을 생성합니다
@Update : 데이터베이스에서 매개변수로 제공된 엔터티 집합을 수정합니다.
@Delete : 매개변수로 제공된 엔터티 집합을 데이터베이스에서 제거합니다.
@Query : DAO 클래스에서 사용되는 주요 주석. 데이터베이스에서 읽기/쓰기 작업을 수행할 수 있습니다.
@Query("SELECT * FROM users")
@Query("SELECT * FROM users WHERE uid IN (:userIds)")
@Query("SELECT * FROM users WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
@Database(entities = arrayOf(User::class), version=1)
abstract class UserDB : RoomDatabase() {
abstract fun userDao(): UserDao
}
val db = Room.databaseBuilder(applicationContext,UserDB::class. java, "userdb").allowMainThreadQueries().build()
val users = db.userDao().getAll()
if(users.isNotEmpty()) {
Log.d("USERDB","something in db")
}
else {
Log.d("USERDB","Nothing in db")
}
allowMainThreadQueries() : Room은 메인쓰레드에서의 데이터베이스 접근을 허용하지 않는다. 허용하고 싶다면 데이터베이스를 생성하는 빌더에서 allowMainThreadQueries()를 호출해야한다. 허용하지 않는 이유는 데이터를 받아오는 작업이 길어질 경우 UI가 장시간 멈춰버릴수 있기 때문이다.
val userd1 = User(1, "jihyeon", "Seo")
val userd2 = User(2, "jihyn", "S")
db.userDao().insertAll(userd1)
db.userDao().insertAll(userd2)
var readuser = db.userDao().findByName("j%", "%")
if (readuser != null) {
Log.d("USERDB", readuser.firstName+" "+readuser.lastName)
}
else {
}
findByName("j%", "%") : "SELECT * FROM users WHERE first_name LIKE W% AND last_name LIKE % LIMIT 1"
-> j로 시작하는 first_name에서 jihyeon Seo 즉, 첫번 째 데이터를 반환하게 됩니다.
Process : 실행 중인 프로그램
안드로이드 시스템은 애플리케이션이 시작될 때 새로운 리눅스 프로세스를 시작합니다.
Thread : 프로세스의 한 부분
단일 or 다중 프로세스를 가질 수 있다.
Android 시스템은 애플리케이션이 시작될 때 단일 스레드로 새로운 Linux 프로세스를 시작합니다.
Android 시스템은 애플리케이션이 시작될 때 단일 스레드로 새로운 Linux 프로세스를 시작합니다. => main thread
main thread에서는 UI제어 또는 관리만 합니다
메인 스레드에서 무거운 작업을 하지 않아야 합니다.
백그라운드 스레드에서 무거은 작업을 수행하기 위해 백그라운드 스레드를 만듭니다.
class BkgThread : Thread() {
override fun run() {
var i=0
while(i<10) {
i += 1
Log.d("BkgThread", "In background thread : $i")
}
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout. activity_main)
var bkgthread = BkgThread()
bkgthread.start()
}
}
방법 2 : Runnable interface 사용하기
class BkgThread : Runnable {
override fun run() {
var i=0
while(i<10) {
i += 1
Log.d("BkgThread", "In background thread : $i")
}
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout. activity_main)
var bkgthread = Thread(BkgThread())
bkgthread.start()
}
}
방법 3 : thread main에서 작동 -> 간단하니깐
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout. activity_main)
thread(start=true) {
var i=0
while(i<10) {
i += 1
Log.d("BkgThread", "In background thread : $i")
}
}
}
}
val myHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val helloText = findViewById<TextView>(R.id.hellotxt)
Log.d("BkgThread", "Main thread")
if(msg.what == 1) {
helloText.setText("${msg.arg1}")
}
}
}
val myHandler = object : Handler(Looper.getMainLooper())
override fun handleMessage(msg: Message)
Thread {
var i=0
while(i<10) {
i += 1
Log.d("BkgThread", "In background thread : $i")
var msg = myHandler.obtainMessage()
msg.what = 1
msg.arg1 = i
myHandler.sendMessage(msg)
Thread.sleep(1000)
}
}.start()
var msg = myHandler.obtainMessage() : 메시지를 보낼 Message 객체 가져오기
msg.what = 1 : 메시지를 구별하기 위한 "what" 속성은 핸들러에서 사용됩니다.
myHandler.sendMessage(msg) : 메인 쓰레드의 메시지 큐에 메시지를 보내기 위해 sendMessage() 메소드를 호출함