2학년 모바일프로그래밍 11주차

서지현·2021년 12월 11일
0

모바일프로그래밍

목록 보기
2/4

SharedPreferences APIs

  • 비교적 작은 키-값 컬렉션을 저장하려면 SharedPreferences API를 사용합니다.

  • 키-값 쌍 데이터를 파일에 저장하고 이를 읽고 쓰는 간단한 방법을 제공합니다.

  • 키-값 쌍을 작성하려면

    1. Get a handle to share preferences
    2. Create Editor
    3. Write to shared preferences
    4. Call apply()
  1. Get a handle to share preferences
 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만 지원

  1. Create Editor
 val editor = sharedPref.edit()
  1. Write to shared preferences
val usernameInput = findViewById<EditText>(R.id.Username)
val passwordInput = findViewById<EditText>(R.id.Password)
val buttonInput = findViewById<Button>(R.id.button)
  1. Call apply()
 editor.apply()

Database using Room

  • 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 : 데이터베이스 내의 테이블을 나타냅니다.
  • DAO : 데이터베이스에 액세스하는 데 사용되는 방법을 포함합니다.
@Entity
data class User(
 @PrimaryKey val uid: Int,
 val firstName: String?,
 val lastName: String?
)

  • 테이블에 다른 이름을 지정하려면 @Entity 주석의 tableName 속성을 설정할수 있다

  • 열에 다른 이름을 지정하려면 필드에 @ColumnInfo 주석을 추가할 수 있다.

@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)")
  • 테이블의 uid 필드가 user Id 매개변수에 있는 사용자 테이블의 모든 데이터를 쿼리 및 반환합니다.
@Query("SELECT * FROM users WHERE first_name LIKE :first AND " +
 "last_name LIKE :last LIMIT 1")
  • 테이블의 first_name 필드가 첫 번째 매개변수와 같고 테이블의 성 필드가 마지막 매개변수와 같은 사용자 테이블의 쿼리 데이터입니다. 쿼리 결과의 첫 번째 데이터만 반환합니다.
@Database(entities = arrayOf(User::class), version=1)
abstract class UserDB : RoomDatabase() {
  abstract fun userDao(): UserDao
}
  • 테이블 구조는 User class로 정의
  • 데이터베이스 구조 버전은 1
  • UserDB 는 추상클래스 -> RoomDatabase class를 상속
  • userDao() : to access data in UserDB.
 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

  • Process : 실행 중인 프로그램

  • 안드로이드 시스템은 애플리케이션이 시작될 때 새로운 리눅스 프로세스를 시작합니다.

  • Thread : 프로세스의 한 부분

  • 단일 or 다중 프로세스를 가질 수 있다.

  • Android 시스템은 애플리케이션이 시작될 때 단일 스레드로 새로운 Linux 프로세스를 시작합니다.

  • Android 시스템은 애플리케이션이 시작될 때 단일 스레드로 새로운 Linux 프로세스를 시작합니다. => main thread

  • main thread에서는 UI제어 또는 관리만 합니다

  • 메인 스레드에서 무거운 작업을 하지 않아야 합니다.

  • 백그라운드 스레드에서 무거은 작업을 수행하기 위해 백그라운드 스레드를 만듭니다.

    • 네트워크 운영
    • 데이터베이스 호출
    • 대용량 파일 읽기
  • background thread 만들기
    방법 1 : Thread() 사용하기
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")
            }
        }
    }
}
  • background thread는 UI 위젯에 접근을 못한다

  • Message Queue
    • 특정 스레드에서 실행될 작업 목록이 있는 큐입니다.
    • 스레드당 하나의 Message Queue만 있습니다.
  • Looper
    • 메시지 대기열을 순환하고 처리할 해당 스레드에 메시지를 보냅니다.
    • 스레드당 하나의 고유 루퍼만 있습니다.
    • 메인 스레드는 자동으로 루퍼를 생성합니다.
  • Handler
    • 스레드의 메시지 대기열과 관련된 메시지 및 실행 가능한 개체를 보내고 처리합니다.
  • main thread
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())

  • Handler 클래스의 객체를 생성합니다.
  • Looper 객체가 필요합니다.
  • getMainLooper() 메서드는 메인 스레드의 루프를 반환합니다.

override fun handleMessage(msg: Message)

  • 수신된 메시지를 처리하려면 handleMessage() 메소드를 재정의한다.
  • background thread
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() 메소드를 호출함

profile
안녕하세요

0개의 댓글

관련 채용 정보