Jank за мобилне апликације — шта је то, узроци и отклањање

Аутор: IT Sectr Објављено: 2026-04-01 Време читања: 10 мин

Jank — термин који означава приметне застоје или „муцање” анимације интерфејса, узроковане прескакањем појединих кадрова. У мобилним апликацијама Jank настаје када време рендеровања кадра премаши буџет који је одређен фреквенцијом освежавања дисплеја. Према Android Developers, 2025, Jank је главни узрок субјективног осећаја „спорости” — апликација може бити функционално савршена, али је корисник доживљава као спору због нестабилног FPS-а.

Главно

  • Jank — прескочени кадрови, приметни као застоји анимације.
  • Главни узрок — прекорачење буџета времена по кадру (16.6 мс за 60 FPS).
  • Jank настаје због тешког Layout-а, дугог GC-а, блокирања main thread-а или overdraw-а.
  • За дијагностику се користе FrameTimeline (Android) и Instruments (iOS).
  • Отклањање Jank-а повећава NPS и задржавање корисника за 15–25%.

Шта је Jank

Jank — термин из области компјутерске графике који означава визуелни дефект при којем се анимација креће трзајима уместо глатког клизања. У мобилном развоју Jank се мери као број прескочених кадрова (skipped frames) у јединици времена. Ако систем не стигне да припреми кадар до тренутка VSync-а, дисплеј понавља претходни кадар — настаје пауза у трајању од 16.6 мс при 60 Hz. Један прескочени кадар може бити неприметан, али серија од 3–5 прескочених кадрова заредом ствара осећај „спорости” у трајању од 50–80 мс, који корисник јасно региструје.

Jank је посебно критичан за анимације које морају да раде константном брзином: скрол листе, анимација отварања менија, паралакс ефекти, прелази између екрана. Према UX истраживању Google-а (2024), апликација са Jank показатељем већим од 3% скрол сесија добија 22% више једноѕвездичних рецензија од апликације са показатељем мањим од 0.5%. Алат Android Vitals аутоматски прати Jank и класификује га по severity: moderate, severe и critical.

Главни узроци Jank-а

Узроци Jank-а деле се у неколико категорија. Прва — Layout Jank: изазван честим requestLayout() због промене димензија View-а, анимација LayoutTransition или динамичког учитавања садржаја. Сваки позив requestLayout покреће Measure + Layout за цело подстабло View-а, што може трајати 5–30 мс. Друга — Draw Jank: повезан са прекомерним цртањем (overdraw) и коришћењем тешких drawable-а. Трећа — Thread Jank: блокирање main thread-а због синхроних операција — учитавање датотека, рад са базом на главној нити, декодирање Bitmap-а.

Четврта категорија — GC Jank: garbage collection у ART/Dalvik или Swift ARC. Када се на хеапу накупи много објеката, GC покреће Stop-The-World паузу у трајању од 5–15 мс. На Android-у GC паузе најчешће настају при честим алокацијама у петљама: креирање објеката у onDraw()-у, алокације у адаптерима, неискоришћени ламбда изрази. Пета — IPC Jank: међупроцесна комуникација (ContentProvider, Binder) на главној нити. Шеста — Rendering Jank: споро рендеровање GPU-а због неоптималних шејдера или текстура велике величине.

Тип Jank-аУзрокТипично трајањеАлат за проналажење
LayoutrequestLayout, relayout5–30 мсPerfetto, Systrace
DrawOverdraw, тешки drawable3–20 мсGPU Profiling
ThreadБлокирање main thread-а10–200 мсAndroid Studio Profiler
GCGarbage Collection5–15 мсMemory Profiler
RenderingОптерећење GPU-а10–50 мсGPU Tracer, Xcode GPU

Дијагностика Jank-а у Android-у

У Android-у дијагностика Jank-а почиње системским трагом Perfetto. Perfetto бележи активност свих нити, CPU-а, GPU-а и планирача. Јасан показатељ Jank-а су линије Choreographer.doFrame и Choreographer.doCallbacks: ако интервал између два узастопна позива doFrame прелази 16.6 мс, кадар је прескочен. Perfetto показује тачан узрок — који system call, lock или GC је изазвао кашњење. У Android Studio Profiler-у слична функционалност је доступна кроз CPU Profiler.

За аутоматско откривање Jank-а у продукцији користи се FrameMetricsAggregator — API који прикупља статистику за сваки кадар и агрегира по сесији. У Android 12+ појавио се PerformanceHintManager — API за сугестије систему о циљној фреквенцији кадрова. Ако апликација укаже да ради у сценарију од 120 FPS, систем може повећати фреквенцију CPU/GPU-а ради спречавања Jank-а. За једноставно логирање свих прескочених кадрова довољно је претплатити се на Choreographer.FrameCallback.

Логирање Jank-а кроз Choreographer

Код у Kotlin-у се претплаћује на Choreographer.FrameCallback и логира сваки прескочени кадар са навођењем трајања кашњења. Callback се позива при сваком VSync-у.

kotlin
class JankDetector {

    private val frameBudget = 16_666_666L
    private var previousFrameTime = 0L

    private val callback =
        Choreographer.FrameCallback { currentTime ->
            if (previousFrameTime != 0L) {
                val frameDuration =
                    currentTime - previousFrameTime
                val skippedFrames =
                    (frameDuration / frameBudget) - 1
                if (skippedFrames > 0) {
                    Log.w("Jank",
                        "Прескочено $skippedFrames кадрова")
                }
            }
            previousFrameTime = currentTime
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

    fun start() {
        Choreographer.getInstance()
            .postFrameCallback(callback)
    }
}

Дијагностика Jank-а у iOS-у

У iOS-у дијагностика Jank-а се обавља кроз Instruments са шаблоном Core Animation. Instruments приказује FPS у реалном времену, број offscreen-рендера и hit-тестове. Главни индикатори Jank-а у iOS-у: црвене колоне на временској скали Core Animation (прекорачење буџета кадра), висок показатељ Renderer (означава offscreen rendering) и низак FPS. За продукцијско праћење MetricKit прикупља извештаје са метриком MXAnimatoryMetric, која укључује просечан FPS, P50 и P95 време кадра.

Изворна дијагностика Jank-а у iOS-у укључује CADisplayLink са провером timestamp и targetTimestamp. Ако тренутни timestamp значајно заостаје за targetTimestamp, значи да је прескочен један или више кадрова. Apple такође препоручује коришћење os_signpost за прилагођено профилисање: постављање signpost-interval на почетку и крају рендеровања кадра и преглед у Instruments-у који интервали прелазе 16.6 мс. У SwiftUI-ју за дијагностику Jank-а користи се UIView.invalidateIntrinsicContentSize — често позивање ове методе указује на нестабилан Layout.

CADisplayLink за детекцију Jank-а

Код у Swift-у одређује прескочене кадрове кроз CADisplayLink. Ако разлика између timestamp и targetTimestamp прелази 16.6 мс — бележи се Jank.

swift
class JankMonitor {

    private var displayLink: CADisplayLink?
    private var totalJank = 0

    func start() {
        displayLink = CADisplayLink(
            target: self,
            selector: #selector(detectJank)
        )
        displayLink?.add(to: .current,
            forMode: .common)
    }

    @objc
    private func detectJank() {
        guard let link = displayLink else { return }
        let delay = link.targetTimestamp
            - link.timestamp
        if delay > 0.0167 {
            totalJank += 1
        }
    }
}

Алати за профилисање Jank-а

За профилисање Jank-а користе се како уграђени алати оперативног система, тако и екстерни SDK-ови. У Android-у кључни алат је Perfetto (заменио Systrace). Perfetto омогућава снимање трагова до 30 секунди и њихову анализу кроз веб интерфејс ui.perfetto.dev. Приказује тачну временску скалу са радом Choreographer-а, нити за рендеровање (RenderThread) и GPU-а. За детаљну анализу проблема са GPU-ом користи се AGI (Android GPU Inspector), који показује не само време кадра већ и оптерећење специфичних блокова GPU-а — шејдера, растеризатора, блока текстура.

У iOS-у аналоган алат је Instruments са шаблонима Core Animation, Metal System Trace и GPU Driver. Core Animation приказује FPS и време кадра, Metal System Trace — рад GPU-а са детаљима до сваког draw call-а. За профилисање на реалним уређајима под оптерећењем користе се Firebase Performance (прикупља метрику Screen Rendering) и Sentry (хвата stack trace при Jank-у). Нови API Android 15 Performance Hint омогућава програмеру да систему назначи који кадрови су важни и да прима упозорења од система када се приближава Jank-у.

FrameMetricsAggregator у продукцији

Код у Kotlin-у користи FrameMetricsAggregator за прикупљање статистике кадрова по сесији. Након заустављања агрегатора приказује се број прескочених кадрова.

kotlin
class JankAggregator(private val activity: Activity) {

    private val aggregator = FrameMetricsAggregator()

    fun startCollection() {
        aggregator.add(activity.window)
    }

    fun stopAndReport() {
        aggregator.remove()
        val result = aggregator.getMetrics()
        val totalFrames = result
            ?.get(FrameMetrics.TOTAL_DURATION)
            ?.size ?: 0
        val jankFrames = result
            ?.get(FrameMetrics.TOTAL_DURATION)
            ?.count { it > 16_666_666L} ?: 0
        Log.d("JankReport",
            "Jank однос: ${jankFrames * 100 / totalFrames}%")
    }
}

Методе отклањања застоја кадрова

Отклањање Jank-а захтева комбинацију метода у зависности од његовог типа. За Layout Jank: замена дубоких хијерархија са ConstraintLayout/Compose/SwiftUI, коришћење merge-тагова, избегавање requestLayout у анимацијама. За Draw Jank: коришћење Debug GPU Overdraw за проналажење 4x+ overdraw-а, замена тешких drawable-а векторским (VectorDrawable/PDF), опрезно коришћење hardware layers — убрзавају рендеровање али троше више GPU меморије. За Thread Jank: премештање свих I/O операција, рада са базом и декодирања Bitmap-а у позадинске нити, коришћење Kotlin Coroutines са одговарајућим Dispatcher-ом или RxJava са Schedulers.io().

За GC Jank: минимизирање алокација у onDraw() и getView(), коришћење пулова објеката (ObjectPool), замена for-each са индексираним for, опрезно коришћење immutable data class у Kotlin-у са copy() — copy креира нови објекат. За IPC Jank: лења иницијализација ContentProvider-а кроз App Startup, премештање Binder позива у позадинску нит. За Rendering Jank: смањење величине текстура до максималне резолуције екрана, коришћење ASTC или ETC2 компресије, избегавање непотребне shader compilation (компајлирање шејдера унапред). Свеобухватно решење — редовно покретање Perfetto/Instruments профилисања у CI-ју и праћење Jank регресија.

Anti-Jank образац: Async Layout

Kotlin код демонстрира асинхроно учитавање података на екран након reportFullyDrawn, како тежак посао не би блокирао први кадар. Callback се позива након што корисник види интерфејс.

kotlin
class JankSafeLoader {

    suspend fun loadAfterFirstFrame(
        activity: Activity
    ) {
        // гарантујемо да је први кадар већ рендерован
        if (Build.VERSION.SDK_INT >= 29) {
            activity.reportFullyDrawn()
        }

        // тешко учитавање — после првог кадра
        withContext(Dispatchers.IO) {
            val data = fetchHeavyData()
            withContext(Dispatchers.Main) {
                updateUI(data)
            }
        }
    }
}

Често постављана питања

Шта је Jank у мобилним апликацијама?

Jank — прескочени кадрови рендеровања који се манифестују као приметни застоји или трзаји анимације. Настаје када време припреме кадра премаши буџет времена (16.6 мс за 60 FPS).

Који су главни узроци Jank-а?

Layout Jank (чести requestLayout), Draw Jank (overdraw), Thread Jank (блокирање main thread-а), GC Jank (garbage collection), IPC Jank (Binder позиви) и Rendering Jank (тешки шејдери).

Како дијагностиковати Jank у Android-у?

Користите Perfetto за системски траг, GPU Profiling за анализу фаза кадра и FrameMetricsAggregator за продукцијско праћење. У Android Studio — CPU Profiler са Deep Java Trace.

Како измерити Jank у iOS-у?

Кроз Instruments са шаблоном Core Animation или Metal System Trace. За продукцију — MetricKit са MXAnimatoryMetric. Програмски — CADisplayLink са провером разлике timestamp и targetTimestamp.

Који проценат Jank-а се сматра критичним?

Према Google-у, Jank показатељ већи од 3% скрол сесија (3 од 100 скролова садрже застој) доводи до пораста негативних рецензија за 22%. Циљни показатељ — мање од 0.5% скрол сесија.

Закључак

  • Jank — прескочени кадрови који изазивају видљиве застоје анимације у мобилним апликацијама.
  • Главни узроци: Layout Jank, Draw Jank, Thread Jank, GC Jank, IPC Jank и Rendering Jank.
  • Дијагностика Jank-а у Android-у — кроз Perfetto, GPU Profiling и FrameMetricsAggregator.
  • Дијагностика Jank-а у iOS-у — кроз Instruments, CADisplayLink и MetricKit.
  • Отклањање Jank-а захтева комбинацију: равне хијерархије, позадинске нити, минимизацију алокација, кеширање.
  • Циљни Jank показатељ — мање од 0.5% скрол сесија са застојима.
  • Редовно профилисање у CI-ју спречава регресије перформанси пре објављивања.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође