시작하기 전에
✔ 프로세스 : 시스템상의 실행 중인 프로그램. 독립된 메모리 공간을 할당받는다.
✔ 스레드 : 하나의 프로세스 상의 독립적인 실행 흐름
✔ 하나의 프로세스는 멀티 스레딩을 지원한다. 따라서, 다수의 스레드로 동시적 처리가 가능하다.
✔ 하나의 프로세스 안에서 동작하는 스레드들은 프로세스의 메모리 공간을 공유할 수 있다.
메인 스레드 (UI 스레드)
✔ 안드로이드 시스템은 새로운 앱을 실행하면 새로운 리눅스 프로세스를 시작한다.
✔ 메인 스레드는 화면의 UI를 그리는 처리를 담당한다.
백그라운드 스레드
✔ 메모리 이외의 다른 곳에서 데이터를 가져오는 모든 작업을 백그라운드 스레드에서 처리하는 것을 권장
✔ 백그라운드 스레드는 UI 구성 요소에 접근하면 안 된다.
Thread 객체
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
var thread = WorkerThread()
thread.start()
}
class WorkerThread: Thread() {
override fun run() {
var i = 0
while (i < 10) {
i += 1
Log.i("WorkerThread", "$i")
}
}
}
Runnable 인터페이스
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
var thread = Thread(WorkerRunnable())
thread.start()
}
class WorkerRunnable: Runnable {
override fun run() {
var i = 0
while (i < 10) {
i += 1
Log.i("WorkerRunnable", "$i")
}
}
}
람다식으로 Runnable 익명객체 구현
✔ 인터페이스 내부에 메서드가 하나만 있는 경우는 람다식으로 변환이 가능하다.
Thread {
var i = 0
while (i < 10) {
i += 1
Log.i("LambdaThread", "$i")
}
}.start()
코틀린에서 제공하는 thread() 구현
✔ 코틀린에서는 thread() 안에 파라미터로 start=true를 전달하면 thread() 안의 코드 블록이 실행된다.
thread (start = true) {
var i = 0
while (i < 10) {
i += 1
Log.i("KotlinThread", "$i")
}
}
핸들러와 루퍼
루퍼 (Looper)
✔ MainActivity가 실행됨과 동시에 생성되어 for 문 하나가 무한루프 돌고 있는 서브 스레드
✔ 메인 스레드는 내부적으로 루퍼를 가지며 루퍼는 Message Queue를 포함한다.
✔ Message Queue : 다른 스레드 혹은 스레드 자기 자신으로부터 전달받은 메시지를 보관하는 Queue
✔ 루퍼 : Message Queue에서 메시지, Runnable 객체를 차례로 꺼내서 핸들러가 처리하도록 전달한다.
✔ 여러 개의 백그라운드에서 큐에 메시지를 입력하면, 입력된 순서대로 하나씩 꺼내서 핸들러에 전달한다.
핸들러 (Handler)
✔ 루퍼가 있는 메인 스레드에서 주로 사용되며, 새로 생성된 스레드들과 메인 스레드와의 통신을 담당한다.
✔ 루퍼로부터 받은 메시지, Runnable 객체를 처리하거나 메시지를 받아서 Message Queue에 넣는 스레드 간의 통신 장치이다.
✔ 핸들러는 루퍼를 통해 전달되는 메시지를 받아서 처리하는 일종의 명령어 처리기로 사용된다.
✔ 앱이 실행되면 자동으로 생성되어 무한루프 도는 루퍼와 다르게 핸들러는 직접 생성해서 사용해야 한다.
메시지 (Message)
✔ 루퍼의 큐에 값을 전달하기 위해 사용되는 클래스
✔ 메시지 객체에 미리 정의해 둔 코드를 입력하고 큐에 담아두면 루퍼가 꺼내서 핸들러에 전달한다.
타이머 앱 만들기
UI
activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
<?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">
<TextView
android:id="@+id/textTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00 : 00"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttonStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="시작"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/buttonStop"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/buttonStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="종료"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/buttonStart" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
cs |
MainActivity.kt
class MainActivity : AppCompatActivity() {
val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
var total = 0 // 전체 시간 저장
var started = false // 시작됨을 체크할 수 있는 변수
val handler = object: Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
val minute = String.format("%02d", total/60)
val second = String.format("%02d", total%60)
binding.textTimer.text = "$minute:$second"
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.buttonStart.setOnClickListener {
started = true
thread(start=true) {
while (started) {
Thread.sleep(1000)
if (started) {
total = total + 1
handler?.sendEmptyMessage(0)
}
}
}
}
binding.buttonStop.setOnClickListener {
if (started) {
started = false
total = 0
binding.textTimer.text = "00:00"
}
}
}
}
'Android > Concept' 카테고리의 다른 글
[Android] [Kotlin] 서비스 (0) | 2021.09.22 |
---|---|
[Android] [Kotlin] 코루틴 (0) | 2021.09.21 |
[Android] [Kotlin] Room 데이터베이스 (0) | 2021.09.19 |
[Android] [Kotlin] SharedPreferences (0) | 2021.09.19 |
[Android] [Kotlin] SQLite (0) | 2021.09.14 |