Diary of Duc

Android - Theard

2018-08-31

Lý do

Mặc định logic code của chúng ta viết sẽ chạy trên Main Thread, hay còn gọi là UI Thread. Nếu có logic code nào đó chạy quá chậm (I/O, thực thiện quá nhiều tính toán, xem thêm) sẽ khiến UI Thread bị chặn vì giao diện không thể phản hồi lại khi chưa thực hiện xong logic code đó, hệ thống sẽ hiện thị hộp thoại ARNs, gây khó chịu cho người dùng.


Vì vậy, những logic code cần nhiều thời gian để hoàn thành nên được chạy trong một Theard khác, khi nào thực hiện xong sẽ báo lại kết quả cho UI Thread.

Chạy trong UI Thread

Thử code như dưới đây:
activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Loading"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

MainActivity.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MainActivity : AppCompatActivity() {

private val length = 3000000000

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
for (i in 0 until length){
if (i == length-1){
text_view.text = "Loaded"
}
}
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show()
}
}

Màn hình sẽ trắng xóa như thế này cho tới khi chạy xong vòng for:

Mãi mới xong :3

(Đừng thắc mắc time trong hình, mình chạy mấy lần mới chụp màn hình đúng lúc được).

Nếu chạy vòng for đó trong Thread khác thì sao? Chịu khó đọc tiếp bên dưới.

Tạo Thread

Để tạo một Thread, có nhiều cách

Implement từ Runnable
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
package com.mduccc.thread

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

private val length = 2000000000

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
newTheard().theard.start()
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show()
}

inner class newTheard: Runnable{

val theard = Thread(this)

override fun run() {
for (i in 0 until length){
if (i == length-1){
runOnUiThread {
text_view.text = "Loaded"
theard.join()
}
}
}
}

}

}

App run lên cái hiện như này luôn, vòng for sẽ chạy trong Thread riêng:

Lúc vòng for chạy xong rồi sẽ setText() mới cho text_view:

Nếu thắc mắc tại sao phải setText() trong runOnUiThread(), thì hãy nhớ ta đang setText() trong 1 luồng không phải UI Theard, do đó nếu muốn thay đổi UI, phải chạy trong UI Theard.

Extend từ Thread
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
class MainActivity : AppCompatActivity() {

private val length = 2000000000

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
newTheard().start()
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show()
}

inner class newTheard: Thread(){

override fun run() {
for (i in 0 until length){
if (i == length-1){
runOnUiThread {
text_view.text = "Loaded"
this.join()
}
}
}
}

}

}
Tạo trong Function

Nếu không muốn tạo một inner class, thì có thể viết nó trong function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MainActivity : AppCompatActivity() {

private val length = 2000000000

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
object : Thread() {
override fun run() {
for (i in 0 until length){
if (i == length-1){
runOnUiThread {
text_view.text = "Loaded"
this.join()
}
}
}
}
}.start()
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show()
}

}

Sự khác biệt giữa Implement RunnableExtend Thread:

* Khi Implement Runnable, vì RunnableInterface, nên ta có thể Extend thêm Class khác
* Khi Extend Thread, vì Thread là một Class, không thể Extend thêm Class khác

Tags: android

URL QR