invalidate() হল Android-এ View ক্লাসের একটি মেথড যা একটি ভিউকে পুনরায় আঁকার প্রয়োজন হিসাবে চিহ্নিত করে। invalidate() কল করলে পরবর্তী স্ক্রিন রিফ্রেশ চক্রে ভিউটির পুনরায় আঁকা ঘটে, যা এটিকে কাস্টম কম্পোনেন্টের ভিজুয়াল অবস্থা আপডেট করার প্রাথমিক প্রক্রিয়া করে তোলে। Android Developers Documentation (2025) অনুসারে, 90% কাস্টম View-এ ডেটা পরিবর্তনগুলিকে স্ক্রিনে প্রদর্শনের সাথে সিঙ্ক্রোনাইজ করতে invalidate() ব্যবহার করা হয়। মেথডটি অ্যাসিঙ্ক্রোনাসভাবে কাজ করে — এটি কেবল dirty ফ্ল্যাগ সেট করে এবং সঙ্গে সঙ্গে নিয়ন্ত্রণ ফিরিয়ে দেয়।
মূল বিষয়
invalidate() হল android.view.View ক্লাসের একটি মেথড যা Android সিস্টেমকে জানায় যে একটি ভিউয়ের ভিজুয়াল উপস্থাপনা পুরানো হয়ে গেছে। মেথডটি কল করার পর, সিস্টেম ভিউটিকে dirty হিসাবে চিহ্নিত করে এবং পরবর্তী স্ক্রিন রিফ্রেশ চক্রে (সাধারণত 60 FPS-এর জন্য 16 ms) এর পুনরায় আঁকার সময় নির্ধারণ করে।
invalidate() মেথডটি বিভিন্ন রূপে আসে: প্যারামিটার ছাড়া (সম্পূর্ণ পুনরায় আঁকা), Rect প্যারামিটার সহ (আংশিক), এবং ltrb প্যারামিটার (left, top, right, bottom) সহ। সব সংস্করণ অ্যাসিঙ্ক্রোনাসভাবে কাজ করে এবং UI থ্রেড থেকে কল করা উচিত। ব্যাকগ্রাউন্ড থ্রেড থেকে কল করার জন্য postInvalidate() রয়েছে।
Android-এ পুনরায় আঁকার প্রক্রিয়া ViewRootImpl-এর উপর ভিত্তি করে — একটি অভ্যন্তরীণ কম্পোনেন্ট যা View Hierarchy-কে আঁকার জন্য Surface-এর সাথে সংযুক্ত করে। যখন invalidate() কল করা হয়, ViewRootImpl ভিউ এলাকাটিকে dirty হিসাবে চিহ্নিত করে এবং Choreographer-এর মাধ্যমে পুনরায় আঁকার অনুরোধ পাঠায় — একটি সিস্টেম সার্ভিস যা স্ক্রিন রিফ্রেশ হারের সাথে আঁকাকে সিঙ্ক্রোনাইজ করে।
Choreographer Vsync থেকে সিগন্যাল পায় এবং একটি ত্রি-পদক্ষেপ প্রক্রিয়া শুরু করে: measure, layout, draw। তবে, invalidate() শুধুমাত্র draw ধাপকে প্রভাবিত করে — measure এবং layout ধাপগুলি কার্যকর করা হয় না যতক্ষণ না requestLayout() কল করা হয়। এটি একটি মূল পার্থক্য: invalidate() requestLayout()-এর চেয়ে সস্তা কারণ এটি জ্যামিতি পুনরায় গণনা করে না।
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() Path-এর মাধ্যমে রেখা আঁকার জন্য Canvas পায়।
invalidate() এবং postInvalidate()-এর মধ্যে প্রধান পার্থক্য থ্রেড নিরাপত্তায়। invalidate() শুধুমাত্র UI থ্রেড (মূল থ্রেড) থেকে কল করা উচিত। postInvalidate() যেকোনো থ্রেড থেকে কল করা যেতে পারে — এটি Handler-এর মাধ্যমে UI থ্রেডে পুনরায় আঁকার অনুরোধ পাঠায়।
| বৈশিষ্ট্য | invalidate() | postInvalidate() |
|---|---|---|
| কল থ্রেড | UI থ্রেড (মূল থ্রেড) | যেকোনো থ্রেড |
| প্রক্রিয়া | সরাসরি dirty ফ্ল্যাগ আপডেট | Handler.post()-এর মাধ্যমে UI থ্রেডে |
| বিলম্ব | সর্বনিম্ন, বর্তমান চক্রে | পরবর্তী UI থ্রেড চক্র পর্যন্ত |
| কর্মক্ষমতা | উচ্চ | Handler-এ সামান্য ওভারহেড |
| সুপারিশ | UI থ্রেডের জন্য সর্বদা invalidate() | শুধুমাত্র ব্যাকগ্রাউন্ড থ্রেডের জন্য |
অনুশীলনে, postInvalidate() নেটওয়ার্ক ডেটা লোডিং, সেন্সর ফলাফল প্রক্রিয়াকরণ বা ব্যাকগ্রাউন্ড গণনার দৃশ্যে ব্যবহৃত হয়। আপনি যদি UI থ্রেডে থাকেন — সর্বনিম্ন বিলম্বের জন্য সর্বদা invalidate() ব্যবহার করুন।
// UI থ্রেড থেকে কল করা হয়েছে
view.invalidate()
// ব্যাকগ্রাউন্ড থ্রেড থেকে কল করা হয়েছে
Thread {
// ভারী গণনা
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) এবং invalidate(int l, int t, int r, int b) পুনরায় আঁকার এলাকা সীমিত করার অনুমতি দেয়। এটি কর্মক্ষমতার জন্য অত্যন্ত গুরুত্বপূর্ণ: যখন একটি View-এর শুধুমাত্র একটি অংশ পরিবর্তিত হয় (যেমন, কার্সার চলাচল, নির্দেশক পরিবর্তন), তখন পুরো ভিউটি পুনরায় আঁকার প্রয়োজন নেই।
সিস্টেম নির্দিষ্ট dirty আয়তক্ষেত্রটি onDraw()-এ canvas.clipBounds-এর মাধ্যমে পাঠায়। onDraw()-এর ভিতরে, আপনি clipBounds পরীক্ষা করতে পারেন এবং শুধুমাত্র সেই এলাকার মধ্যে আঁকতে পারেন, যদিও Android Canvas স্বয়ংক্রিয়ভাবে dirty আয়তক্ষেত্রের বাইরে আঁকা ক্লিপ করে।
// আংশিক আপডেট: শুধুমাত্র কার্সার এলাকা
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) এডিটর, আঁকা ক্যানভাস এবং অ্যানিমেটেড কম্পোনেন্টের জন্য একটি অপরিহার্য কৌশল।
একটি সাধারণ ভুল হল requestLayout() কল করা যেখানে invalidate() যথেষ্ট হবে, এবং এর বিপরীত। পার্থক্যটি মৌলিক: invalidate() শুধুমাত্র draw ধাপকে প্রভাবিত করে, যেখানে requestLayout() একটি সম্পূর্ণ measure → layout → draw চক্র শুরু করে।
| দিক | invalidate() | requestLayout() |
|---|---|---|
| চক্রের ধাপ | শুধুমাত্র draw | measure + layout + draw |
| কখন ব্যবহার করবেন | শুধুমাত্র রেন্ডারিং পরিবর্তিত হয় (রঙ, পাঠ্য, গ্রাফিক্স) | View-এর আকার বা অবস্থান পরিবর্তিত হয় |
| কর্মক্ষমতা | হালকা — শুধুমাত্র পুনরায় আঁকা | ভারী — শ্রেণিবিন্যাস পুনরায় গণনা |
| শ্রেণিবিন্যাসের উপর প্রভাব | শুধুমাত্র বর্তমান View | পিতৃ পাত্রগুলিকে প্রভাবিত করতে পারে |
আপনি যদি TextView-এ পাঠ্য পরিবর্তন করেন, তাহলে invalidate() যথেষ্ট কারণ View-এর আকার পরিবর্তন হয় না। যদি পাঠ্য একটি নতুন লাইনে যেতে পারে এবং উচ্চতা বাড়াতে পারে, তাহলে requestLayout() প্রয়োজন। Android Lint কর্মক্ষমতা নিয়মের মাধ্যমে এই ধরনের ত্রুটিগুলি ট্র্যাক করতে সহায়তা করে।
অতিরিক্ত invalidate() কলগুলি Android-এ কাস্টম View-এর খারাপ কর্মক্ষমতার প্রধান কারণগুলির মধ্যে একটি। আসুন অপ্টিমাইজেশন কৌশলগুলি দেখি।
যদি ডেটা উচ্চ ফ্রিকোয়েন্সিতে (সেন্সর, অ্যানিমেশন, ভিডিও) আপডেট হয়, তাহলে প্রতিটি পরিবর্তনে invalidate() কল করবেন না। স্ক্রিন রিফ্রেশ হারের সাথে সিঙ্ক্রোনাইজ করতে ValueAnimator বা Choreographer.FrameCallback ব্যবহার করুন। এটি নিশ্চিত করে যে invalidate() প্রতি ফ্রেমে একবারের বেশি কল না হয়।
API 14 থেকে, Android GPU-এর মাধ্যমে হার্ডওয়্যার এক্সিলারেশন সমর্থন করে। যদি আপনার কাস্টম View শুধুমাত্র Canvas API (drawRect, drawCircle, drawPath) ব্যবহার করে, তাহলে এক্সিলারেশন স্বচ্ছভাবে কাজ করে। DisplayList-সামঞ্জস্যপূর্ণ অপারেশনের জন্য, invalidate() উল্লেখযোগ্যভাবে দ্রুত প্রক্রিয়া করা হয়।
// Vsync সিঙ্কের জন্য Choreographer ব্যবহার করা
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
লক্ষ্যযুক্ত আপডেটের জন্য invalidate(Rect) ব্যবহার করুন, onDraw() থেকে invalidate() কল করা এড়িয়ে চলুন (অন্তহীন লুপ), এবং সর্বদা ডিভাইসে GPU Profile Rendering-এর মাধ্যমে প্রোফাইল করুন। এটি প্রতিটি ফ্রেমের সঠিক রেন্ডারিং সময় দেখাবে এবং সমস্যা এলাকাগুলি চিহ্নিত করতে সাহায্য করবে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
না, onDraw()-এর ভিতরে invalidate() কল করলে একটি অন্তহীন পুনরায় আঁকা লুপ তৈরি হয়: onDraw() invalidate() কল করে, যা আবার onDraw() ট্রিগার করে। এটি CPU-র 100% ব্যবহার এবং ফ্রেম ড্রপের কারণ হয়। ValueAnimator বা Choreographer-এর মাধ্যমে অ্যানিমেশন ব্যবহার করুন।
invalidate() শুধুমাত্র UI থ্রেডে কাজ করে এবং সঙ্গে সঙ্গে dirty ফ্ল্যাগ আপডেট করে। postInvalidate() Handler-এর মাধ্যমে UI থ্রেডে একটি অনুরোধ পাঠায় এবং যেকোনো ব্যাকগ্রাউন্ড থ্রেড থেকে কল করা যেতে পারে। আপনি যদি UI থ্রেডে থাকেন — সর্বনিম্ন বিলম্বের জন্য invalidate() ব্যবহার করুন।
হ্যাঁ, অভ্যন্তরীণভাবে TextView-এর setText() মেথড পাঠ্য আপডেট করার পর invalidate() কল করে। যদি পাঠ্য View-এর মাত্রা পরিবর্তন করে, তাহলে অতিরিক্তভাবে requestLayout() কল করা হয়। স্ট্যান্ডার্ড উইজেটগুলির সাথে কাজ করার সময় ডেভেলপারদের ম্যানুয়ালি invalidate() কল করার প্রয়োজন নেই।
প্রতিটি invalidate() কল পরবর্তী Vsync-এ (প্রতি 16 ms) পুনরায় আঁকার সময় নির্ধারণ করে। যদি onDraw() 16 ms-এর বেশি সময় নেয়, তাহলে ফ্রেম ড্রপ হয়। onDraw() অপ্টিমাইজ করুন — Bitmap ক্যাশ করুন, বরাদ্দ এড়িয়ে চলুন, এবং GPU রেন্ডারিংয়ের জন্য হার্ডওয়্যার এক্সিলারেশন ব্যবহার করুন।
হ্যাঁ, Paint বৈশিষ্ট্য (রঙ, পুরুত্ব, শৈলী) পরিবর্তনের পরে, আপনাকে invalidate() কল করতে হবে, কারণ View স্বয়ংক্রিয়ভাবে Paint অবজেক্টের পরিবর্তনগুলি ট্র্যাক করে না। সিস্টেম জানে না যে Paint পরিবর্তিত হয়েছে এবং স্পষ্ট অনুরোধ ছাড়া onDraw() কল করবে না।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন