invalidate() — Android-də View sinfinin metodudur ki, görünüşü yenidən çəkilmə tələb edən kimi qeyd edir. invalidate() çağırışı görünüşün ekran yeniləmə dövrünün ən yaxın vaxtında yenidən çəkilməsinə səbəb olur və bu, onu xüsusi komponentlərin vizual vəziyyətini yeniləməyin əsas mexanizminə çevirir. Android Developers Documentation (2025) məlumatına görə, invalidate() məlumat dəyişikliklərini ekranda göstərilmə ilə sinxronizasiya etmək üçün 90% xüsusi View-lərdə istifadə olunur. Metod asinxron işləyir — o, sadəcə dirty flagını təyin edir və dərhal idarəetməni qaytarır.
Əsas məqamlar
invalidate() — android.view.View sinfinin metodudur ki, Android sisteminə görünüşün vizual təsvirinin köhnəldiyini bildirir. Metod çağırıldıqdan sonra sistem görünüşü dirty kimi qeyd edir və onun yenidən çəkilməsini ekran yeniləmə dövrünün ən yaxın vaxtında planlaşdırır (adətən 60 FPS üçün 16 ms).
invalidate() metodu müxtəlif formalar qəbul edir: parametrsiz (tam yenidənçəkmə), Rect parametri ilə (qismən) və ltrb parametrləri ilə (left, top, right, bottom). Bütün versiyalar asinxron işləyir və UI thread-dən çağırıla bilər. Fon thread-lərdən çağırış üçün postInvalidate() mövcuddur.
Android-də yenidənçəkmə mexanizmi ViewRootImpl üzərində qurulub — View Hierarchy-ni çəkmə üçün Surface ilə birləşdirən daxili komponent. invalidate() çağırıldıqda, ViewRootImpl görünüş sahəsini dirty olaraq qeyd edir və Choreographer — ekran yeniləmə tezliyi ilə çəkməni sinxronizasiya edən sistem xidməti vasitəsilə yenidənçəkmə sorğusu göndərir.
Choreographer Vsync-dən siqnal alır və üçlü keçid işə salır: measure, layout, draw. Lakin invalidate() yalnız draw fazasına təsir edir — measure və layout fazaları requestLayout() çağırılmadıqca icra olunmur. Bu əsas fərqdir: invalidate() requestLayout()-dan daha yüngüldür, çünki həndəsəni yenidən hesablamır.
class CustomChartView(context: Context, attrs: AttributeSet?)
: View(context, attrs) {
private var dataPoints: List<Float> = emptyList()
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
fun updateData(newPoints: List<Float>) {
dataPoints = newPoints
invalidate() // Yenidənçəkmə sorğusu
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.BLUE
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
// Qrafik xəttinin çəkilməsi
val path = Path()
dataPoints.forEachIndexed { index, value ->
val x = index * width / max(dataPoints.size - 1, 1)
val y = height - value * height
if (index == 0) path.moveTo(x, y)
else path.lineTo(x, y)
}
canvas.drawPath(path, paint)
}
}
Bu nümunədə, qrafik çəkmək üçün xüsusi View məlumat yenilənəndə invalidate() çağırır. Sistem yalnız bu View-i yenidən çəkir, iyerarxiyanın qalan elementlərinə təsir etmir. onDraw() Path vasitəsilə xətlər çəkmək üçün Canvas alır.
invalidate() və postInvalidate() arasındakı əsas fərq thread təhlükəsizliyindədir. invalidate() yalnız UI thread-dən (main thread) çağırılmalıdır. postInvalidate() istənilən thread-dən çağırıla bilər — Handler vasitəsilə yenidənçəkmə sorğusunu UI thread-ə göndərir.
| Xüsusiyyət | invalidate() | postInvalidate() |
|---|---|---|
| Çağırış thread-i | UI thread (main thread) | İstənilən thread |
| Mexanizm | Dirty flag-ın birbaşa yenilənməsi | Handler.post() vasitəsilə UI thread-ə |
| Gecikmə | Minimal, cari dövrdə | Növbəti UI thread dövrünə qədər |
| Performans | Yüksək | Handler üzrə kiçik əlavə yük |
| Tövsiyə | UI thread üçün həmişə invalidate() | Yalnız fon thread-ləri üçün |
Praktikada postInvalidate() şəbəkədən məlumat yükləmə, sensor nəticələrinin işlənməsi və ya fon hesablamaları ssenarilərində istifadə olunur. UI thread-dəsinizsə — minimum gecikmə üçün həmişə invalidate() istifadə edin.
// UI thread-dən çağırıldı
view.invalidate()
// Fon thread-dən çağırıldı
Thread {
// Ağır hesablamalar
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) və invalidate(int l, int t, int r, int b) yenidənçəkmə sahəsini məhdudlaşdırmağa imkan verir. Bu, performans üçün kritikdir: View-in yalnız bir hissəsi yenilənərkən (məsələn, kursor hərəkəti, göstərici dəyişməsi) bütün görünüşü yenidən çəkməyin mənası yoxdur.
Sistem göstərilən dirty düzbucaqlını onDraw()-a canvas.clipBounds vasitəsilə ötürür. onDraw() daxilində clipBounds yoxlanıla bilər və yalnız bu sahə daxilində çəkmə aparıla bilər, baxmayaraq ki, Android Canvas avtomatik olaraq dirty düzbucaqlıdan kənar çəkməni kəsir.
// Qismən yeniləmə: yalnız kursor sahəsi
private val cursorRect = Rect()
fun moveCursorTo(newX: Int, newY: Int) {
// Köhnə mövqeyi etibarsız et
invalidate(cursorRect)
cursorRect.set(newX - 5, newY - 5,
newX + 5, newY + 5)
// Yeni mövqeyi etibarsız et
invalidate(cursorRect)
}
Qismən yenidənçəkmə olmadan, hər bir kursor hərəkəti bütün View-i yenidən çəkərdi ki, bu da böyük qrafik üçün bir neçə onluq əvəzinə minlərlə pikselin yenidən çəkilməsi deməkdir. invalidate(Rect) — redaktorlar, çəkmə canvasları və animasiya edilmiş komponentlər üçün məcburi texnikadır.
Ümumi səhvlərdən biri requestLayout()-u invalidate()-in kifayət etdiyi yerdə çağırmaq və əksinə. Fərq əsaslıdır: invalidate() yalnız draw fazasına təsir edir, requestLayout() isə tam measure → layout → draw dövrünü işə salır.
| Aspekt | invalidate() | requestLayout() |
|---|---|---|
| Dövr fazaları | Yalnız draw | measure + layout + draw |
| Nə vaxt istifadə edilməli | Yalnız çəkmə dəyişir (rəng, mətn, qrafika) | Görünüşün ölçüsü və ya mövqeyi dəyişir |
| Performans | Yüngül — yalnız yenidənçəkmə | Ağır — iyerarxiyanın yenidən hesablanması |
| İyerarxiyaya təsir | Yalnız cari görünüş | Valideyn konteynerlərə təsir edə bilər |
TextView-də mətni dəyişirsinizsə — invalidate() kifayətdir, çünki görünüşün ölçüsü dəyişmir. Əgər mətn yeni sətirə keçib hündürlüyü artıra bilərsə — requestLayout() lazımdır. Android Lint performans qaydaları vasitəsilə bu cür səhvləri izləməyə kömək edir.
Həddindən artıq invalidate() çağırışları — Android-də xüsusi View-lərin aşağı performansının əsas səbəblərindən biridir. Optimallaşdırma texnikalarına baxaq.
Əgər məlumatlar yüksək tezliklə yenilənirsə (sensorlar, animasiya, video), hər dəyişiklikdə invalidate() çağırmayın. Ekran yeniləmə tezliyi ilə sinxronizasiya üçün ValueAnimator və ya Choreographer.FrameCallback istifadə edin. Bu, invalidate()-in kadr başına bir dəfədən çox çağırılmamasını təmin edir.
API 14-dən etibarən Android GPU vasitəsilə aparat sürətləndirilməsini dəstəkləyir. Əgər xüsusi View yalnız Canvas API (drawRect, drawCircle, drawPath) istifadə edirsə, sürətləndirmə şəffaf işləyir. DisplayList-uyğun əməliyyatlar üçün invalidate() əhəmiyyətli dərəcədə sürətli işlənir.
// Vsync sinxronizasiyası üçün Choreographer istifadə etməklə
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
Nöqtəvi yeniləmələr üçün invalidate(Rect) istifadə edin, onDraw() daxilindən invalidate() çağırmaqdan çəkinin (sonsuz dövr) və həmişə cihazda GPU Profile Rendering vasitəsilə profil çəkin. Bu, hər kadrın çəkilməsinin dəqiq vaxtını göstərəcək və problemli yerləri müəyyən etməyə kömək edəcək.
Tez-tez verilən suallar
Xeyr, onDraw() daxilində invalidate() çağırışı sonsuz yenidənçəkmə dövrü yaradır: onDraw() invalidate() çağırır, bu da yenidən onDraw()-u işə salır. Bu, CPU-nun 100% yüklənməsinə və kadr itkisinə səbəb olur. ValueAnimator və ya Choreographer vasitəsilə animasiyalardan istifadə edin.
invalidate() yalnız UI thread-də işləyir və dirty flag-ı dərhal yeniləyir. postInvalidate() Handler vasitəsilə UI thread-ə sorğu göndərir və istənilən fon thread-dən çağırıla bilər. UI thread-dəsinizsə — minimum gecikmə üçün invalidate() istifadə edin.
Bəli, TextView daxilində setText() metodu mətn yeniləndikdən sonra invalidate() çağırır. Əgər mətn görünüşün ölçülərini dəyişibsə, əlavə olaraq requestLayout() çağırılır. Standart vidjetlərlə işləyərkən tərtibatçı əl ilə invalidate() çağırmalı deyil.
Hər invalidate() çağırışı növbəti Vsync-də (hər 16 ms) yenidənçəkmə planlaşdırır. onDraw() 16 ms-dən uzun çəkərsə, kadr itkisi baş verir. onDraw()-u optimallaşdırın — Bitmap-i keşləyin, alokasiyalardan qaçının və GPU çəkməsi üçün Hardware Acceleration istifadə edin.
Bəli, Paint xüsusiyyətlərini (rəng, qalınlıq, üslub) dəyişdikdən sonra invalidate() çağırmaq lazımdır, çünki View Paint obyektlərindəki dəyişiklikləri avtomatik izləmir. Sistem Paint-in dəyişdiyini bilmir və açıq sorğu olmadan onDraw()-u çağırmayacaq.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun