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() vs postInvalidate()

Η κύρια διαφορά μεταξύ invalidate() και postInvalidate() είναι η ασφάλεια νημάτων. Το invalidate() πρέπει να καλείται μόνο από το νήμα UI (κύριο νήμα). Το postInvalidate() μπορεί να κληθεί από οποιοδήποτε νήμα — μέσω Handler στέλνει αίτημα επανασχεδίασης στο νήμα UI.

Χαρακτηριστικόinvalidate()postInvalidate()
Νήμα κλήσηςΝήμα UI (κύριο νήμα)Οποιοδήποτε νήμα
ΜηχανισμόςΆμεση ενημέρωση dirty flagΜέσω Handler.post() στο νήμα UI
ΚαθυστέρησηΕλάχιστη, στον τρέχοντα κύκλοΜέχρι τον επόμενο κύκλο νήματος UI
ΑπόδοσηΥψηλήΜικρό overhead στο 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 ορθογώνιο στο onDraw() μέσω canvas.clipBounds. Μέσα στο 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, που για ένα μεγάλο γράφημα σημαίνει επανασχεδίαση χιλιάδων pixel αντί για μερικές δεκάδες. invalidate(Rect) — υποχρεωτική τεχνική για επεξεργαστές, καμβάδες σχεδίασης και κινούμενα στοιχεία.

invalidate() vs 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() όταν εργάζεται με τυπικά widget.

Πώς επηρεάζει το invalidate() την απόδοση στα 60 FPS;

Κάθε κλήση invalidate() προγραμματίζει επανασχεδίαση στο επόμενο Vsync (κάθε 16 ms). Εάν το onDraw() διαρκεί περισσότερο από 16 ms, συμβαίνει απώλεια καρέ. Βελτιστοποιήστε το onDraw() — κάντε cache το Bitmap, αποφύγετε δεσμεύσεις μνήμης και χρησιμοποιήστε Hardware Acceleration για σχεδίαση GPU.

Πρέπει να καλείται invalidate() μετά την αλλαγή ιδιοτήτων Paint;

Ναι, μετά την αλλαγή ιδιοτήτων 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 δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης