Jank — is een term die merkbare haperingen of “stotteren” van de interface-animatie aanduidt, veroorzaakt door het overslaan van afzonderlijke frames. In mobiele apps treedt Jank op wanneer de renderingtijd van een frame het budget overschrijdt dat is toegewezen door de verversingssnelheid van het display. Volgens Android Developers, 2025 is Jank de belangrijkste oorzaak van het subjectieve gevoel van “vertraging” — de app kan functioneel perfect zijn, maar de gebruiker ervaart hem als traag vanwege een instabiele FPS.
Belangrijkste punten
Jank — is een term uit de computergrafiek die een visueel defect aanduidt waarbij de animatie schokkerig beweegt in plaats van vloeiend te glijden. In mobiele ontwikkeling wordt Jank gemeten als het aantal overgeslagen frames (skipped frames) per tijdseenheid. Als het systeem er niet in slaagt een frame te prepareren vóór het VSync-moment, herhaalt het display het vorige frame — er ontstaat een pauze van 16.6 ms bij 60 Hz. Eén overgeslagen frame kan onmerkbaar zijn, maar een reeks van 3–5 opeenvolgende overgeslagen frames creëert een gevoel van “vertraging” van 50–80 ms, dat de gebruiker duidelijk registreert.
Jank is vooral kritisch voor animaties die met constante snelheid moeten werken: scrollen van lijsten, animatie van menu-openen, parallax-effecten, overgangen tussen schermen. Volgens UX-onderzoek van Google (2024) krijgt een app met een Jank-indicator van meer dan 3% scrollsessies 22% meer éénsterrecensies dan een app met een indicator van minder dan 0.5%. De tool Android Vitals volgt automatisch Jank en classificeert het op severity: moderate, severe en critical.
De oorzaken van Jank zijn onderverdeeld in verschillende categorieën. De eerste — Layout Jank: veroorzaakt door frequente requestLayout()-aanroepen door veranderingen in View-afmetingen, LayoutTransition-animaties of dynamisch laden van inhoud. Elke requestLayout-aanroep start Measure + Layout voor de gehele View-subboom, wat 5–30 ms kan duren. De tweede — Draw Jank: gerelateerd aan overdraw en het gebruik van zware drawables. De derde — Thread Jank: blokkering van de main thread door synchrone bewerkingen — bestanden laden, werken met de database op de hoofdthread, Bitmap-decodering.
De vierde categorie — GC Jank: garbage collection in ART/Dalvik of Swift ARC. Wanneer zich veel objecten ophopen in de heap, start GC een Stop-The-World-pauze van 5–15 ms. Op Android treden GC-pauzes het vaakst op bij frequente allocaties in lussen: objecten maken in onDraw(), allocaties in adapters, ongebruikte lambda-expressies. De vijfde — IPC Jank: interprocescommunicatie (ContentProvider, Binder) op de hoofdthread. De zesde — Rendering Jank: trage GPU-rendering door niet-optimale shaders of texturen van grote afmetingen.
| Type Jank | Oorzaak | Typische duur | Zoektool |
|---|---|---|---|
| Layout | requestLayout, relayout | 5–30 ms | Perfetto, Systrace |
| Draw | Overdraw, zware drawable | 3–20 ms | GPU Profiling |
| Thread | Blokkering main thread | 10–200 ms | Android Studio Profiler |
| GC | Garbage Collection | 5–15 ms | Memory Profiler |
| Rendering | GPU-belasting | 10–50 ms | GPU Tracer, Xcode GPU |
In Android begint de diagnose van Jank met de systeemtrace Perfetto. Perfetto registreert de activiteit van alle threads, CPU, GPU en planner. Een duidelijke indicator van Jank zijn de regels Choreographer.doFrame en Choreographer.doCallbacks: als het interval tussen twee opeenvolgende doFrame-aanroepen meer dan 16.6 ms bedraagt, is het frame overgeslagen. Perfetto toont de exacte oorzaak — welke system call, lock of GC de vertraging veroorzaakte. In Android Studio Profiler is vergelijkbare functionaliteit beschikbaar via CPU Profiler.
Voor automatische detectie van Jank in productie wordt FrameMetricsAggregator gebruikt — een API die statistieken per frame verzamelt en aggregeert per sessie. In Android 12+ is PerformanceHintManager verschenen — een API voor hints aan het systeem over de beoogde framesnelheid. Als de app aangeeft in een 120 FPS-scenario te werken, kan het systeem de CPU/GPU-frequentie verhogen om Jank te voorkomen. Voor eenvoudige logging van alle overgeslagen frames is het voldoende om je te abonneren op Choreographer.FrameCallback.
Kotlin-code abonneert zich op Choreographer.FrameCallback en logt elk overgeslagen frame met vermelding van de vertragingsduur. De callback wordt bij elke VSync aangeroepen.
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 frames overgeslagen")
}
}
previousFrameTime = currentTime
Choreographer.getInstance()
.postFrameCallback(this)
}
fun start() {
Choreographer.getInstance()
.postFrameCallback(callback)
}
}
In iOS wordt de diagnose van Jank uitgevoerd via Instruments met de Core Animation-sjabloon. Instruments toont realtime FPS, het aantal offscreen-renders en hit-tests. De belangrijkste indicatoren van Jank in iOS: rode kolommen op de Core Animation-tijdschaal (overschrijding van het framebudget), een hoge Renderer-indicator (duidt op offscreen rendering) en lage FPS. Voor productiemonitoring verzamelt MetricKit rapporten met de MXAnimatoryMetric, die gemiddelde FPS, P50 en P95-frametijd omvat.
Native Jank-diagnose in iOS omvat CADisplayLink met controle van timestamp en targetTimestamp. Als de huidige timestamp aanzienlijk achterloopt op targetTimestamp, zijn een of meer frames overgeslagen. Apple raadt ook aan om os_signpost te gebruiken voor aangepaste profilering: plaats een signpost-interval aan het begin en einde van de framerendering en controleer in Instruments welke intervallen de 16.6 ms overschrijden. In SwiftUI wordt voor Jank-diagnose UIView.invalidateIntrinsicContentSize gebruikt — frequent aanroepen van deze methode duidt op een instabiele Layout.
Swift-code detecteert overgeslagen frames via CADisplayLink. Als het verschil tussen timestamp en targetTimestamp meer dan 16.6 ms bedraagt — wordt Jank geregistreerd.
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
}
}
}
Voor Jank-profilering worden zowel ingebouwde OS-tools als SDK's van derden gebruikt. In Android is de belangrijkste tool Perfetto (verving Systrace). Perfetto maakt het mogelijk traces van maximaal 30 seconden op te nemen en te analyseren via de webinterface ui.perfetto.dev. Het toont de exacte tijdlijn met de activiteit van Choreographer, rendering-threads (RenderThread) en GPU. Voor gedetailleerde analyse van GPU-problemen wordt AGI (Android GPU Inspector) gebruikt, dat niet alleen de frametijd toont, maar ook de belasting van specifieke GPU-blokken — shaders, rasterizer, textuurblok.
In iOS is het equivalent Instruments met de sjablonen Core Animation, Metal System Trace en GPU Driver. Core Animation toont FPS en frametijd, Metal System Trace — GPU-activiteit tot op elke draw call. Voor profilering op echte apparaten onder belasting worden Firebase Performance (verzamelt Screen Rendering-metrics) en Sentry (vangt stack trace bij Jank) gebruikt. De nieuwe Android 15 Performance Hint API stelt de ontwikkelaar in staat om het systeem aan te geven welke frames belangrijk zijn en om waarschuwingen van het systeem te ontvangen bij naderende Jank.
Kotlin-code gebruikt FrameMetricsAggregator voor het verzamelen van framestatistieken per sessie. Na het stoppen van de aggregator wordt het aantal overgeslagen frames weergegeven.
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-ratio: ${jankFrames * 100 / totalFrames}%")
}
}
Het verhelpen van Jank vereist een combinatie van methoden afhankelijk van het type. Voor Layout Jank: diepe hiërarchieën vervangen door ConstraintLayout/Compose/SwiftUI, merge-tags gebruiken, requestLayout in animaties vermijden. Voor Draw Jank: Debug GPU Overdraw gebruiken om 4x+ overdraw te vinden, zware drawables vervangen door vector (VectorDrawable/PDF), voorzichtig met hardware layers — ze versnellen rendering maar verbruiken meer GPU-geheugen. Voor Thread Jank: alle I/O-bewerkingen, databasewerk en Bitmap-decodering verplaatsen naar achtergrondthreads, Kotlin Coroutines met de juiste Dispatcher of RxJava met Schedulers.io() gebruiken.
Voor GC Jank: allocaties in onDraw() en getView() minimaliseren, objectpools (ObjectPool) gebruiken, for-each vervangen door geïndexeerde for, voorzichtig met immutable data class in Kotlin met copy() — copy creëert een nieuw object. Voor IPC Jank: ContentProvider lui initialiseren via App Startup, Binder-aanroepen verplaatsen naar een achtergrondthread. Voor Rendering Jank: textuurgrootte verkleinen tot de maximale schermresolutie, ASTC- of ETC2-compressie gebruiken, onnodige shader compilation vermijden (shaders vooraf compileren). Een complete oplossing — regelmatig Perfetto/Instruments-profilering in CI en het volgen van Jank-regressies.
Kotlin-code demonstreert asynchroon laden van gegevens op het scherm na reportFullyDrawn, zodat zwaar werk het eerste frame niet blokkeert. De callback wordt aangeroepen nadat de gebruiker de interface ziet.
class JankSafeLoader {
suspend fun loadAfterFirstFrame(
activity: Activity
) {
// garanderen dat het eerste frame al is gerenderd
if (Build.VERSION.SDK_INT >= 29) {
activity.reportFullyDrawn()
}
// zware belading — na het eerste frame
withContext(Dispatchers.IO) {
val data = fetchHeavyData()
withContext(Dispatchers.Main) {
updateUI(data)
}
}
}
}
Veelgestelde vragen
Jank — zijn overgeslagen renderingframes die zich manifesteren als merkbare haperingen of schokken in de animatie. Het ontstaat wanneer de voorbereidingstijd van een frame het tijdbudget overschrijdt (16.6 ms voor 60 FPS).
Layout Jank (frequente requestLayout), Draw Jank (overdraw), Thread Jank (blokkering main thread), GC Jank (garbage collection), IPC Jank (Binder-aanroepen) en Rendering Jank (zware shaders).
Gebruik Perfetto voor systeemtraces, GPU Profiling voor analyse van framefasen en FrameMetricsAggregator voor productiemonitoring. In Android Studio — CPU Profiler met Deep Java Trace.
Via Instruments met de Core Animation- of Metal System Trace-sjabloon. Voor productie — MetricKit met MXAnimatoryMetric. Programmatisch — CADisplayLink met controle van het verschil tussen timestamp en targetTimestamp.
Volgens Google leidt een Jank-indicator van meer dan 3% scrollsessies (3 van de 100 scrolls bevatten een hapering) tot een toename van negatieve recensies met 22%. Streefindicator — minder dan 0.5% scrollsessies.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook