invalidate() — چیست، مکانیزم ترسیم مجدد و invalidate(Rect)

نویسنده: IT Sectr منتشر شده: 2026-07-20 زمان مطالعه: 7 دقیقه

invalidate() — متدی از کلاس View در Android است که ویو را به عنوان نیازمند ترسیم مجدد علامت‌گذاری می‌کند. فراخوانی invalidate() منجر به ترسیم مجدد ویو در نزدیک‌ترین چرخه به‌روزرسانی صفحه می‌شود و آن را به مکانیزم اصلی به‌روزرسانی وضعیت بصری کامپوننت‌های سفارشی تبدیل می‌کند. بر اساس Android Developers Documentation (2025)، invalidate() در 90% Viewهای سفارشی برای همگام‌سازی تغییرات داده‌ها با نمایش روی صفحه استفاده می‌شود. این متد به صورت ناهمگام کار می‌کند — فقط پرچم dirty را تنظیم کرده و بلافاصله کنترل را برمی‌گرداند.

نکات اصلی

  • invalidate() — درخواست ناهمگام ترسیم مجدد View در Android، از طریق مکانیزم dirty flag کار می‌کند
  • postInvalidate() — نسخه invalidate() برای فراخوانی از رشته پس‌زمینه، ایمن از نظر رشته
  • invalidate(Rect) — ترسیم مجدد جزئی فقط ناحیه مشخص شده برای بهینه‌سازی عملکرد
  • onDraw() — متدی که توسط سیستم پس از invalidate() فراخوانی می‌شود، مشابه draw(_:) در iOS
  • invalidate() vs requestLayout() — invalidate() محتوا را دوباره ترسیم می‌کند، requestLayout() هندسه را دوباره محاسبه می‌کند

invalidate() در Android چیست

invalidate() — متدی از کلاس android.view.View است که به سیستم Android اطلاع می‌دهد نمایش بصری ویو منسوخ شده است. پس از فراخوانی متد، سیستم ویو را به عنوان dirty علامت‌گذاری کرده و ترسیم مجدد آن را در نزدیک‌ترین چرخه به‌روزرسانی صفحه برنامه‌ریزی می‌کند (معمولاً 16 ms برای 60 FPS).

متد invalidate() اشکال مختلفی دارد: بدون پارامتر (ترسیم مجدد کامل)، با پارامتر Rect (جزئی) و با پارامترهای ltrb (left, top, right, bottom). همه نسخه‌ها به صورت ناهمگام کار می‌کنند و می‌توانند از رشته UI فراخوانی شوند. برای فراخوانی از رشته‌های پس‌زمینه postInvalidate() وجود دارد.

ترسیم مجدد از طریق invalidate() چگونه کار می‌کند

مکانیزم ترسیم مجدد در Android بر اساس ViewRootImpl است — کامپوننت داخلی که View Hierarchy را به Surface برای ترسیم متصل می‌کند. هنگامی که invalidate() فراخوانی می‌شود، ViewRootImpl ناحیه ویو را به عنوان dirty علامت‌گذاری کرده و از طریق Choreographer — سرویس سیستمی که ترسیم را با فرکانس به‌روزرسانی صفحه همگام می‌کند — درخواست ترسیم مجدد ارسال می‌کند.

چرخه ترسیم مجدد

Choreographer سیگنال Vsync را دریافت کرده و یک گذر سه‌گانه را اجرا می‌کند: measure، layout، draw. با این حال invalidate() فقط روی فاز draw تأثیر می‌گذارد — فازهای measure و layout اجرا نمی‌شوند مگر اینکه requestLayout() فراخوانی شده باشد. این تفاوت کلیدی است: invalidate() سبک‌تر از requestLayout() است زیرا هندسه را دوباره محاسبه نمی‌کند.

kotlin
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() // درخواست ترسیم مجدد
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        paint.color = Color.BLUE
        paint.strokeWidth = 4f
        paint.style = Paint.Style.STROKE

        // رسم خط نمودار
        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)
    }
}

در این مثال، یک View سفارشی برای ترسیم نمودار هنگام به‌روزرسانی داده‌ها invalidate() را فراخوانی می‌کند. سیستم فقط این View را دوباره ترسیم می‌کند و بر سایر عناصر سلسله‌مراتب تأثیر نمی‌گذارد. onDraw() Canvas را برای ترسیم خطوط از طریق Path دریافت می‌کند.

invalidate() در مقابل postInvalidate()

تفاوت اصلی بین invalidate() و postInvalidate() در ایمنی رشته است. invalidate() باید فقط از رشته UI (main thread) فراخوانی شود. postInvalidate() را می‌توان از هر رشته‌ای فراخوانی کرد — از طریق Handler درخواست ترسیم مجدد را به رشته UI ارسال می‌کند.

ویژگیinvalidate()postInvalidate()
رشته فراخوانیرشته UI (رشته اصلی)هر رشته‌ای
مکانیزمبه‌روزرسانی مستقیم dirty flagاز طریق Handler.post() به رشته UI
تأخیرحداقل، در چرخه جاریتا چرخه بعدی رشته UI
عملکردبالاسربار کوچک روی Handler
توصیهبرای رشته UI همیشه invalidate()فقط برای رشته‌های پس‌زمینه

در عمل، postInvalidate() در سناریوهای بارگذاری داده از شبکه، پردازش نتایج سنسورها یا محاسبات پس‌زمینه استفاده می‌شود. اگر در رشته UI هستید — همیشه برای حداقل تأخیر از invalidate() استفاده کنید.

kotlin
    // فراخوانی شده از رشته UI
view.invalidate()

    // فراخوانی شده از رشته پس‌زمینه
Thread {
    // محاسبات سنگین
    val result = performHeavyCalculation()
    runOnUiThread {
        updateUi(result)
    }
}.start()

ترسیم مجدد جزئی از طریق invalidate(Rect)

invalidate(Rect) و invalidate(int l, int t, int r, int b) امکان محدود کردن ناحیه ترسیم مجدد را فراهم می‌کنند. این برای عملکرد بسیار مهم است: هنگام به‌روزرسانی فقط بخشی از View (مثلاً حرکت مکان‌نما، تغییر نشانگر) ترسیم مجدد کل ویو بی‌معنی است.

سیستم مستطیل dirty مشخص شده را از طریق canvas.clipBounds به onDraw() منتقل می‌کند. در داخل onDraw() می‌توان clipBounds را بررسی کرد و فقط در محدوده این ناحیه ترسیم کرد، اگرچه Android Canvas به طور خودکار ترسیم را خارج از مستطیل dirty محدود می‌کند.

kotlin
    // به‌روزرسانی جزئی: فقط ناحیه مکان‌نما
private val cursorRect = Rect()

fun moveCursorTo(newX: Int, newY: Int) {
    // موقعیت قدیمی را نامعتبر کن
    invalidate(cursorRect)

    cursorRect.set(newX - 5, newY - 5,
                  newX + 5, newY + 5)

    // موقعیت جدید را نامعتبر کن
    invalidate(cursorRect)
}

بدون ترسیم مجدد جزئی، هر حرکت مکان‌نما کل View را دوباره ترسیم می‌کرد که برای یک نمودار بزرگ به معنای ترسیم مجدد هزاران پیکسل به جای چند ده عدد است. invalidate(Rect) — یک تکنیک اجباری برای ویرایشگرها، بوم‌های نقاشی و کامپوننت‌های متحرک است.

invalidate() در مقابل requestLayout(): تفاوت در چیست

یکی از اشتباهات رایج فراخوانی requestLayout() جایی است که invalidate() کافی است، و برعکس. تفاوت اساسی است: invalidate() فقط روی فاز draw تأثیر می‌گذارد، در حالی که requestLayout() چرخه کامل measure → layout → draw را اجرا می‌کند.

جنبهinvalidate()requestLayout()
فازهای چرخهفقط drawmeasure + layout + draw
کی استفاده کنیمفقط ترسیم تغییر می‌کند (رنگ، متن، گرافیک)اندازه یا موقعیت ویو تغییر می‌کند
عملکردسبک — فقط ترسیم مجددسنگین — محاسبه مجدد سلسله‌مراتب
تأثیر بر سلسله‌مراتبفقط ویو جاریمی‌تواند بر کانتینرهای والد تأثیر بگذارد

اگر متن را در TextView تغییر می‌دهید — invalidate() کافی است، زیرا اندازه ویو تغییر نمی‌کند. اگر متن ممکن است به خط جدید منتقل شده و ارتفاع را افزایش دهد — requestLayout() نیاز است. Android Lint از طریق قوانین عملکرد به ردیابی چنین خطاهایی کمک می‌کند.

بهینه‌سازی عملکرد invalidate()

فراخوانی‌های بیش از حد invalidate() — یکی از دلایل اصلی عملکرد پایین Viewهای سفارشی در Android است. تکنیک‌های بهینه‌سازی را بررسی می‌کنیم.

فرکانس فراخوانی را به حداقل برسانید

اگر داده‌ها با فرکانس بالا به‌روزرسانی می‌شوند (سنسورها، انیمیشن، ویدیو)، در هر تغییر invalidate() را فراخوانی نکنید. برای همگام‌سازی با فرکانس به‌روزرسانی صفحه از ValueAnimator یا Choreographer.FrameCallback استفاده کنید. این تضمین می‌کند که invalidate() بیش از یک بار در هر فریم فراخوانی نمی‌شود.

از Hardware Acceleration استفاده کنید

از API 14 Android شتاب سخت‌افزاری را از طریق GPU پشتیبانی می‌کند. اگر View سفارشی شما فقط از Canvas API (drawRect، drawCircle، drawPath) استفاده می‌کند، شتاب به صورت شفاف کار می‌کند. برای عملیات سازگار با DisplayList، invalidate() به طور قابل توجهی سریع‌تر پردازش می‌شود.

kotlin
// استفاده از Choreographer برای همگام‌سازی Vsync
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
    updateAnimation(frameTimeNanos)
    invalidate()
    Choreographer.getInstance().postFrameCallback(this)
}

fun startAnimation() {
    Choreographer.getInstance().postFrameCallback(frameCallback)
}

برای به‌روزرسانی‌های نقطه‌ای از invalidate(Rect) استفاده کنید، از فراخوانی invalidate() از داخل onDraw() خودداری کنید (حلقه بی‌نهایت) و همیشه با GPU Profile Rendering روی دستگاه پروفایل بگیرید. این زمان دقیق ترسیم هر فریم را نشان داده و به شناسایی نقاط مشکل‌دار کمک می‌کند.

سوالات متداول

آیا می‌توان invalidate() را از onDraw() فراخوانی کرد؟

خیر، فراخوانی invalidate() در داخل onDraw() یک حلقه بی‌نهایت ترسیم مجدد ایجاد می‌کند: onDraw() invalidate() را فراخوانی می‌کند که دوباره onDraw() را اجرا می‌کند. این منجر به 100% بار CPU و افت فریم می‌شود. از انیمیشن‌ها از طریق ValueAnimator یا Choreographer استفاده کنید.

invalidate() چه تفاوتی با postInvalidate() دارد؟

invalidate() فقط در رشته UI کار می‌کند و dirty flag را فوراً به‌روزرسانی می‌کند. postInvalidate() درخواست را از طریق Handler به رشته UI ارسال می‌کند و می‌تواند از هر رشته پس‌زمینه‌ای فراخوانی شود. اگر در رشته UI هستید — برای حداقل تأخیر از invalidate() استفاده کنید.

آیا setText() در TextView به طور خودکار invalidate() را فراخوانی می‌کند؟

بله، در داخل TextView متد setText() پس از به‌روزرسانی متن invalidate() را فراخوانی می‌کند. اگر متن ابعاد ویو را تغییر داده باشد، به طور اضافی requestLayout() فراخوانی می‌شود. توسعه‌دهنده نیازی به فراخوانی دستی invalidate() هنگام کار با ویجت‌های استاندارد ندارد.

invalidate() چگونه بر عملکرد در 60 FPS تأثیر می‌گذارد؟

هر فراخوانی invalidate() ترسیم مجدد را در Vsync بعدی (هر 16 ms) برنامه‌ریزی می‌کند. اگر onDraw() بیشتر از 16 ms طول بکشد، افت فریم رخ می‌دهد. onDraw() را بهینه کنید — Bitmap را کش کنید، از تخصیص حافظه خودداری کنید و برای ترسیم GPU از Hardware Acceleration استفاده کنید.

آیا پس از تغییر ویژگی Paint باید invalidate() فراخوانی شود؟

بله، پس از تغییر ویژگی‌های Paint (رنگ، ضخامت، سبک) باید invalidate() فراخوانی شود، زیرا View تغییرات اشیاء Paint را به طور خودکار ردیابی نمی‌کند. سیستم نمی‌داند که Paint تغییر کرده است و بدون درخواست صریح onDraw() را فراخوانی نمی‌کند.

خلاصه

  • invalidate() — مکانیزم اصلی درخواست ترسیم مجدد View در Android، از طریق dirty flag به صورت ناهمگام کار می‌کند
  • postInvalidate() — نسخه ایمن از نظر رشته برای فراخوانی از رشته‌های پس‌زمینه، از Handler استفاده می‌کند
  • invalidate(Rect) — ترسیم مجدد جزئی فقط ناحیه مشخص شده، برای عملکرد در تغییرات نقطه‌ای حیاتی است
  • requestLayout() — چرخه کامل measure + layout + draw را اجرا می‌کند، بسیار سنگین‌تر از invalidate()
  • Choreographer — سرویس سیستمی همگام‌سازی با Vsync، برای انیمیشن‌ها با invalidate() توصیه می‌شود
  • Hardware Acceleration — شتاب GPU از API 14 در دسترس است، پردازش invalidate() را برای Canvas API تسریع می‌کند
  • GPU Profile Rendering — ابزار پروفایل برای اندازه‌گیری زمان ترسیم و شناسایی onDraw()های کند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید