Main Thread — mobil ilovalarda butun foydalanuvchi interfeysini qayta ishlaydigan asosiy bajarish threadi: teginishlar, chizish, layout yangilanishi va animatsiyalar. iOS da bu RunLoop.main, Android da — Looper.getMainLooper(). Bu threaddagi har qanday uzoq operatsiya UI ni bloklaydi va ANR (Android) yoki interfeysning muzlashiga (iOS) sabab bo'ladi. Apple UIKit Documentation ga ko'ra, UI sinflari thread xavfsiz emas va faqat Main Thread dan chaqirilishini talab qiladi.
Asosiy
Main Thread — bu operatsion tizim tomonidan ilova ishga tushirilganda yaratiladigan va barcha foydalanuvchi interfeysi hodisalarini qayta ishlash uchun mas'ul bo'lgan threaddir. Mobil platformalar kontekstida Main Thread UI Thread deb ham ataladi, chunki chizish, teginishlarni qayta ishlash va animatsiyalar bilan bog'liq barcha operatsiyalar unda bajariladi. Har bir ilova aynan bitta Main Thread ga ega va barcha UI frameworklari (UIKit, AppKit, Android Views, Compose UI) thread-unsafe — ular boshqa threadlardan chaqirilganda to'g'ri ishlashni kafolatlamaydi.
Arxitektura jihatidan Main Thread Event Loop patternini amalga oshiradi: thread cheksiz ravishda yangi hodisalarni (teginishlar, tizim bildirishnomalari, taymerlar) kutadi va ularni navbat tartibida qayta ishlaydi. Bir hodisa qayta ishlanayotganda, keyingisi navbatda kutadi. Agar qayta ishlash 100-200 millisekunddan ortiq davom etsa, foydalanuvchi kechikishni (jank) sezadi. Agar 5 soniyadan ortiq (Android) bo'lsa — tizim ANR (Application Not Responding) dialogini ko'rsatadi va ilovani yopishni taklif qiladi.
Main Threadni tushunishning ahamiyatini ortiqcha baholash qiyin: bu mobil ilovalardagi 90% ishlash muammolarining manbai. Dasturchilar ko'pincha og'ir operatsiyalarni (tarmoq, fayllar, JSON tahlili, tasvir siqish) fon threadlariga o'tkazishni unutadilar. Emulatorda 10 millisekundda bajariladigan operatsiya, real qurilmada sekin disk bilan 500 millisekund davom etishi va sezilarli lagga olib kelishi mumkin.
Thread-unsafe UI frameworklari — UIKit (2007) va Android (2008) ning birinchi versiyalarida qabul qilingan arxitektura qarori. Asosiy sabab — ishlash: UI komponentlariga kirishni blokirovkalar (locks) orqali sinxronlashtirish har bir chizish operatsiyasiga qo'shimcha yuk beradi. Buning o'rniga frameworklar barcha UI o'zgarishlari qat'iy ravishda bitta threadda bajarilishini talab qiladi, race conditionni overheadsiz bartaraf etadi.
Tasavvur qiling, ikkita fon threadi bir vaqtning o'zida textView.setText() ni chaqiradi. Agar UI thread-safe bo'lsa, ikkala chaqiruv mutex orqali sinxronlashtirilar edi, bu chizishni 20-40% sekinlashtirar edi. Hozirgi arxitekturada fon threadidan har qanday UI chaqiruvi yoki e'tiborga olinmaydi yoki crashga sabab bo'ladi (iOS da — Main Thread Checker Exception, Android da — CalledFromWrongThreadException). Istisno — Android da SurfaceView va TextureView, bu erda chizish alohida threaddan bajarilishi mumkin.
Zamonaviy mobil frameworklar (SwiftUI, Jetpack Compose) bu cheklovni saqlaydi: SwiftUI State va ObservedObject dagi barcha o'zgarishlar Main Thread da bo'lishini talab qiladi, garchi chizishning o'zi qisman fon threadlariga o'tkazilgan bo'lsa ham. Jetpack Compose ham State ni Main Thread da o'zgartirishni kutadi. Istisno — drawBehind va layout bilan bog'liq Compose modifierlari, aniq hujjatlashtirish bilan boshqa threadlardan chaqirilishi mumkin.
DispatchQueue.main — iOS da Main Thread ga kod yuborishning asosiy mexanizmi. Bu ilovaning asosiy RunLoop ga bog'langan serial navbatdir. Unga yuborilgan barcha bloklar ketma-ket, kelish tartibida bajariladi. SwiftUI va UIKit avtomatik ravishda yangilanadi, agar siz State ni o'zgartirsangiz yoki setNeedsLayout() ni Main Thread dan chaqirsangiz. Fon vazifasidan natijani asinxron qaytarish uchun DispatchQueue.main.async {} dan foydalaning.
Objective-C-Swift ko'prigida shuningdek Thread.isMainThread mavjud — joriy kodning asosiy threadda bajarilayotganligini tekshiruvchi xususiyat. Mavjud UIKit loyihalari uchun bu standart pattern: if Thread.isMainThread { updateUI() } else { DispatchQueue.main.async { updateUI() } }. SwiftUI da bu tekshirish odatda talab qilinmaydi, chunki framework o'zi body va modifier ning Main Thread da chaqirilishini kafolatlaydi.
import UIKit
class ViewController: UIViewController {
let imageView = UIImageView()
func loadImageFromNetwork() {
// Fon threadi: tasvirni yuklash
DispatchQueue.global(qos: .background).async { [weak self] in
guard let url = URL(string: "https://example.com/image.png"),
let data = try? Data(contentsOf: url),
let image = UIImage(data: data)
else { return }
// UI yangilash uchun Main Thread ga qaytish
DispatchQueue.main.async {
self?.imageView.image = image
self?.imageView.setNeedsLayout()
}
}
}
// Kodning Main Thread da bajarilishini tekshirish
func safeUpdateUI() {
if Thread.isMainThread {
updateUI()
} else {
DispatchQueue.main.async {
self.updateUI()
}
}
}
private func updateUI() {
print("UI Main Thread da yangilandi")
}
}
loadImageFromNetwork() misoli to'g'ri patternni ko'rsatadi: URLSession yoki Data(contentsOf:) DispatchQueue.global orqali fon threadda bajariladi, so'ngra natija UIImageView ni yangilash uchun DispatchQueue.main ga qaytariladi. DispatchQueue.main.async bo'lmasa, ilova fon threadidan UIKit chaqirganda NSInternalInconsistencyException bilan ishdan chiqadi.
iOS da Main Thread da kod bajarishning eng ishonchli usuli — DispatchQueue.main.async orqali aniq yuborish. Agar siz allaqachon Main Thread da bo'lsangiz ham, async yuborish muammo tug'dirmaydi: GCD uni RunLoop ning keyingi iteratsiyasida qayta ishlaydi. Sinxron bajarish uchun DispatchQueue.main.sync dan foydalaning, lekin bu Main Thread dan sync chaqirsangiz deadlock ga olib kelishi mumkin. Qoida: natijani qaytarish uchun async, faqat asosiy threadda emasligingizga kafolat bo'lsa sync.
RunLoop.main — bu iOS ning asosiy hodisalar navbati bilan bog'liq CFRunLoop obyekti. U kirish manbalarini (touch events), taymerlarni va DispatchQueue.main bloklarini qayta ishlaydi. Har bir chizish kadri (60/120 FPS) VSync dan oldin RunLoop da barcha operatsiyalarning tugashini talab qiladi. Main Thread da operatsiyalar 16.6 ms (60 FPS) yoki 8.3 ms (120 FPS) dan ortiq davom etsa, ilova kadrlarni o'tkazib yuboradi, bu vizual ravishda jank yoki stutter sifatida namoyon bo'ladi.
Looper.getMainLooper() — Android da asosiy thread bilan ishlashning asosiy mexanizmi. Android dagi har bir Main Thread Looper ga ega, u navbatdan (MessageQueue) cheksiz ravishda xabarlarni chiqaradi va qayta ishlash uchun Handler ga uzatadi. Activity.runOnUiThread() va View.post() — bu Handler(Looper.getMainLooper()) ustidagi yuqori darajali o'ramlardir. Dispatchers.Main bilan Kotlin Coroutines — asosiy threadga qaytishning zamonaviy usuli.
Android shuningdek StrictMode ni taqdim etadi — Main Thread ni bloklaydigan operatsiyalarni aniqlash vositasi. StrictMode.setThreadPolicy() sizga siyosat belgilash imkonini beradi: asosiy threadda tarmoq chaqiruvlarini taqiqlash (NetworkPolicy), diskdan o'qish (DiskRead), diskka yozish (DiskWrite). Siyosat buzilganda istisno yaratiladi yoki logcat ga xabar yoziladi.
// Android: Main Thread va Kotlin Coroutines bilan ishlash
import android.os.Bundle
import android.widget.TextView
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.net.URL
class MainActivity : ComponentActivity() {
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
textView = TextView(this)
setContentView(textView)
// Misol: asinxron ma'lumot yuklash
lifecycleScope.launch {
val result = loadData() // Dispatchers.IO da bajariladi
textView.text = result // UI Main Thread da
}
}
private suspend fun loadData(): String {
return withContext(Dispatchers.IO) {
URL("https://api.example.com/data").readText()
}
}
}
// StrictMode Main Thread buzilishlarini aniqlash uchun
class App : Application() {
override fun onCreate() {
super.onCreate()
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build()
)
}
}
Kotlin misolida Dispatchers.Main ni lifecycleScope.launch orqali va Dispatchers.IO ni withContext orqali to'g'ri ishlatish ko'rsatilgan. Barcha tarmoq ishi IO-dispatcherda bajariladi, TextView yangilanishi esa avtomatik ravishda Main Thread da, chunki lifecycleScope dagi launch standart bo'yicha Dispatchers.Main dan foydalanadi. Application.onCreate() dagi StrictMode asosiy threaddagi tasodifiy tarmoq chaqiruvlari va disk operatsiyalarini ushlaydi.
Main Thread Checker — Xcode ga o'rnatilgan vosita (Xcode 9 dan mavjud), UIKit, AppKit va boshqa UI frameworklarining fon threadlaridan chaqiruvlarini topadi. Debug vaqtida Main Thread Checker barcha UI-API chaqiruvlarini tahlil qiladi va buzilish aniqlanganda batafsil stack trace bilan breakpoint ko'rsatadi. Haqiqiy qurilmalarda (release versiyasida) Main Thread Checker ishlamaydi — buzilishlar crash yoki noto'g'ri xatti-harakat sifatida namoyon bo'ladi.
Android da analog StrictMode (yuqorida tavsiflangan) va ichki log detektori: fon threadidan View.setText() yoki View.invalidate() chaqirilganda Android CalledFromWrongThreadException ni tashlaydi. Qo'shimcha ravishda Android Studio Profiler Main Thread da qaysi operatsiyalar bajarilayotganini ko'rsatadi. Main Thread da tarmoq yoki fayl operatsiyalarini ko'rsangiz — bu muammoning aniq belgisidir.
| Vosita | Platforma | Nimani aniqlaydi |
|---|---|---|
| Main Thread Checker | iOS (Xcode) | Fon threadlaridan UIKit/AppKit chaqiruvlari |
| StrictMode | Android | Tarmoq, disk, Main Thread dagi uzoq operatsiyalar |
| Android Studio Profiler | Android | Main Thread yukining vaqt bo'yicha vizuallashuvi |
| Time Profiler | iOS (Instruments) | Main Thread da metodlarning bajarilish vaqtini o'lchash |
| HUD / DispatchQueue.main.async | iOS | Debug orqali UI bloklanishining vizual ko'rsatkichi |
Main Thread bloklanishining eng sezilarli simptomi — janky scroll (uziluvchan scroll). Foydalanuvchi UITableView yoki RecyclerView ni aylantirganda, tizim keyingi kadr 16 ms ichida tayyor bo'lishini kutadi. Main Thread da tasvir dekodlash yoki JSON tahlili bajarilsa, kadr chizish kechikadi va foydalanuvchi silkinishlarni ko'radi. Diagnostika uchun profiler dan foydalaning: agar prepareDisplay() yoki layoutSubviews() metodi >16 ms davom etsa — ma'lumotlar noto'g'ri threadda qayta ishlanmoqda.
Birinchi stsenariy — Main Thread da URLConnection yoki Data(contentsOf:) orqali sinxron tarmoq so'rovi. Android da StrictMode detectNetwork() bilan darhol bu buzilishni ushlaydi. iOS da sinxron URLSession aniq xato bermaydi, lekin UI so'rov vaqti davomida (1-10 soniya) muzlaydi. Yechim: asinxron callback bilan URLSession.dataTask (iOS) yoki Retrofit/OkHttp (Android) dan foydalaning.
Ikkinchi stsenariy — tasvirlarni dekodlash va siqish. Android da asosiy threadda UIImage(data:) yoki BitmapFactory.decodeResource() — jank ning eng keng tarqalgan sabablaridan biri. 4000x3000 pikselli tasvir 50-150 millisekundda dekodlanadi, bu 16 ms limitidan oshadi. Yechim: fon threadida dekodlashni kafolatlaydigan ImageLoader (Kingfisher, Coil, Glide) dan foydalaning.
Uchinchi stsenariy — JSON tahlili. Main Thread da JSONSerialization (iOS) yoki JSONObject (Android) orqali API javobini tahlil qilish. Hatto 100 KB li kichik JSON 5-15 millisekundda tahlil qilinadi, lekin sekin qurilmalarda — 50 millisekundgacha. Boshqa operatsiyalar bilan birgalikda bu to'planadi va o'tkazib yuborilgan kadrlarga olib keladi. Yechim: fon threadida parse() chaqiruvi bilan kotlinx.serialization/Decodable dan foydalaning, Main Thread da faqat natijani belgilashni qoldiring.
Tez-tez so'raladigan savollar
Main Thread — ilovaning asosiy threadi, unda barcha UI operatsiyalari bajariladi: teginishlarni qayta ishlash, ekranni chizish, animatsiyalar, layout yangilanishi. iOS da bu RunLoop.main va DispatchQueue.main, Android da — Looper.getMainLooper(). Barcha UI frameworklari (UIKit, Android Views) thread-unsafe va faqat Main Thread dan chaqirishni talab qiladi. Bu threaddagi har qanday uzoq operatsiya interfeysni bloklaydi.
UI frameworklari arxitektura jihatidan ishlash uchun thread-unsafe: blokirovkalar orqali kirish sinxronizatsiyasi har bir chizish operatsiyasiga 20-40% qo'shimcha yuk beradi. UIKit va Android dasturchilari bir thread modelini tanladilar, unda race condition mutexsiz bartaraf etiladi. Barcha UI o'zgarishlari qat'iy ravishda Main Thread da bajarilishi kerak — aks holda crash yoki noto'g'ri ko'rinish.
iOS da kod yuborish uchun DispatchQueue.main.async { } dan foydalaning. Android da — runOnUiThread { } yoki Dispatchers.Main bilan Kotlin Coroutines. Zamonaviy yondashuv — korutinlar: fon ishi uchun withContext(Dispatchers.IO) va launch da avtomatik Dispatchers.Main. Java loyihalari uchun Handler(Looper.getMainLooper()).post { }.
ANR (Application Not Responding) — Android dialogi, Main Thread 5 soniyadan ortiq bloklanganda paydo bo'ladi. ANR tizim kirish hodisasiga (teginish, tugma bosish) ilovadan javob olmaganligini yoki BroadcastReceiver 10 soniya ichida tugamaganligini bildiradi. Sabab — Main Thread dagi sinxron operatsiya: tarmoq so'rovi, ma'lumotlar bazasi bilan ishlash, murakkab hisoblar. iOS da analog — dialogsiz UI muzlashi.
SwiftUI avtomatik ravishda body va modifier ning Main Thread da bajarilishini kafolatlaydi. Biroq, fon threadidan @Published xususiyatlari yoki State ni o'zgartirish (masalan, URLSession delegate dan) muammolarga olib kelishi mumkin. ObservableObject sinflari uchun @MainActor dan foydalaning, shunda ularning barcha metodlari Main Thread da bajariladi. SwiftUI 5.5+ da @MainActor ObservableObject uchun avtomatik qo'shiladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.
Shuningdek o'qing