‫Handler , Looper , MessageQueue , Thread در اندروید

Handler,Looper,MessageQueue,Threadارتباط
Handler,Looper,MessageQueue,Threadارتباط


میخوام تو این پست خیلی ساده وروان درمورد ارتباطات بین Looper, MessageQueue,Handler,Thread بگم . دقت کنید هدفم اینه براتون بگم اینا بطور کلی چی ان ؟ و چه ارتباطی باهم دارن !

البته پیشنهاد میکنم بعد این، داک اندروید رو بخونی که بیشتر و کاملتر درک کنی :) ولی خب توضیح کلی اینه :


?اول اینکه Thread در اندروید چیه و کاربردش چیه ؟

بطور کلی وقتی اپلیکیشن اندروید لانچ میشه سیستم اندروید شروع میکنه یک پراسسی رو نیو میکنه و در یک ترد اون رو اجرا میکنه .و هرکامپوننتی ک شما بسازین ، پیش فرض در همین پراسس و ترد اجرا میشه . که به این ترد پیش فرض میگیم "mainThread" یا "uiThread" .

چرا ترد ؟ باید گفت اندروید یک سیستم عامل مولتی تسک هست .یعنی چی؟ یعنی چندتا کارو همزمان انجام میده (مثلا هم درحال ارتباط با سرور هست و هم یک موزیک درحال پخش و ...) و تردها هم در بحث مولتی تسک مطرح میشن .همانطور ک گفتیم پیش فرض یک ترد بیشتر نداریم (مین ترد) و از طرفی اگر بخوای همزمان چندتا کاررو انجام بدیم باید چیکار کنیم ؟ خب میایم و یک ترد جدید میسازیم وکارهامونو توش اجرا میکنیم (بهش میگن workerThread)

نکته : برای کارهای خیلی کوتاه ترد نزنیم چون تخصیص منابع و آزاد کردن منابع به هرترد ،خودش بیشتر از اون کار زمان میبره


?حالا MessageQueue و Looperو Handler این وسط چی ان ؟

باید گفت تردها در اندروید با تردها در جاهای دیگه فرق دارن و ترد ها در اندروید حاوی messageQueue ها هستن (صفی از تسک ها ؛ "Message ها و Runnable ها " ) ، که توسط Looper این میسج کیوهاا و رانیبل ها مدیریت و اجرا میشن .(لوپر از اسمش پیداس تو یک حلقه یکی یکی میسج و رانیبلهارو اجرا میکنه )

نکته : mainThread پیش فرض لوپر و میسج کیو داره .اما اگر ترد جدیدی ایجاد کردین حتما باید با دستور Looper.Preapre() و Looper.loop() لوپر رو ایجاد کنید.
نکته :هر ترد میتونه تنها یک لوپر ایجاد کنه وگرنه کرش رخ میده.
(توسط threadLocal این قضیه هندل شده . (در پست های بعد درموردش توضیح خواهم داد)


?حالا این Message و Runnable در میسج کیو چی ان ؟

میسج Message : یک پیامه ک حاوی یک پیام دلخواه هست مثل باندل یا ابجکت یا اینت .

رانیبلRunnable : هرکلاسی که بخواد توسط thread اجرا شه باید اینترفیس رانیبل رو پیاده کنه و در متد run هم کاری ک میخواد توسط ترد انجام شه رو مینویسیم


?اما Message و Runnable از کجا وتوسط چی وارد MessageQueue میشن ؟

جواب میشه : Handler

بعبارتی بطور مستقیم نمیتونیم میسج یا رانیبلی رو به میسج کیوهاا بفرستیم ! بلکه از طریق هندلر اینکار انجام میشه. پس ازطریق هندلرهاا میسج ها و runnable ها میرن تو MessageQueue وهرموقع نوبت اجراش شد میدش به هندلری که داده بودش ب صف ، تا اونو پردازش کنه.(شکل زیر)

نکته :اگر هندلر ، Runnable به صف بفرسته ، لوپر به وقت اجراش، خودش اونو پردازش میکنه
و اگر میسج به صف بفرسته ، لوپر میسج رو به همون هندلری که ارسالش کرده بود میفرسته تا اون پردازشش کنه! (توسط کال بک handleMessage هندلرمون ، میتونیم میسج ارسالی رو دریافت کنیم.


Handler,Looper,MessageQueue,Threadارتباط
Handler,Looper,MessageQueue,Threadارتباط


? کمی بیشتر درمورد Handler

به طور کلی کارش میشه " ارسال و پردازش message ها و runnableها "

به صورت جزیی تر میشه گفت این کارهارو باهاش میشه انجام داد :

ارتباط بین تردها با ترد مین // اجرای دستور در زمانی مشخص// ارسال Message بین Threadها // انجام کاری بصورت دوره ای و …
** البته ما بیشتر وقتی اسم هندلرو میشنویم میگیم کارش ارتباط با تردمین هست !درحالی که پیش فرض چنین چیزی صادق نیست !مگر شما اون هندلر رو درترد مین ایجاد کرده باشید ! یا اگر در ترد دیگری ایجاد کردید لوپرمین رو بهش پاس بدید !

نکته : وقتی ترد جدید نیو میکنیم و در اون Looper ایجاد میکنیم ، اون ترد مجهز میشه به یک میسج کیو و لوپر!
حالا بخواهیم به میسج کیو، میسج و رانیبلهارو بفرستیم چیکار میکنیم ؟ بله از طریق هندلر میفرستیم !
و وقتی هندلر نیو میکنیم پیش فرض وصل میشه به لوپر و صف ترد جاری مون !!!
برااینکه از تردجاری ب ترد مین و صف اون وصل شیم تا بتونیم پیام یا کاری رو در ترد مین انجام بدیم باید در کانستراکتور handler، لوپر مین رو پاس بدیم !! مث زیر :
new Thread(new Runnable() {
    @Override
    public void run() {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                //update ui 
            }
        });    } });


? مثال کاربردی از چیزهایی که گفتیم :

فرض کنید قراره با کلیک کاربر بر روی یک button بعد 5 ثانیه ، یک درخواست به سرور بفرستیم.نکته اینجاس اگر کاربر ده بار روی این دکمه کلیک کرد ، قاعدتا باید آخریش لحاظ شه و اون قبلی ها ایگنور و حذف شن.(این کارو با روشهای مختلف میشه انجام داد اما ما اینجا با هندلر میخوایم هندل کنیم)


نمونه کدی که اینکارو انجام میده براتون :


خب ابتدا در بخش 2 یک نمونه هندلر ایجاد و کال بک handleMessage رو همانند تصویر بالا پیاده می کنیم تا 5 ثانیه بعد ازآخرین کلیک ،این قسمت فراخوانی بشه و اینجا میتونیم بفهمیم از آخرین کلیک کاربر 5ثانیه گذشته و وقتشه اطلاعات user رو به سرور ارسال کنیم.

در بخش 3 در رویداد کلیک باتن باید دوکار انجام بدیم :

  • یک Message بسازیم و اطلاعات user رو در اون بریزیم .
  • اخرین میسجی که در کلیکهای قبلیمون فرستادیم رو حذف کنیم تا آخرین فقط درنظر گرفته شه .(من میسج رو برحسب user و ثابت Message_ID پاک میکنم .یعنی میگم اگر میسجی حاوی این ایدی درMessageQueu ها بود اون رو حذف کن .و اخرین دوباره به صف میسج ها بفرست .
  • ابجکت message رو از طریق نمونه handler به صف میسج ها میفرستیم تا به وقتش ، یعنی بعد 5ثانیه اجرا شه .

به خروجی لاگ نگاه کنید :

خروجی کد
خروجی کد

در ثانیه های 30و31و32و33 کلیک شده و آخرین کلیک در زمان 33 رو در نظر گرفته و 5 ثانیه بعد، یعنی 38 ، میسج در بخش handleMessage قابل دریافت و پردازش و استفاده جهت ارسال به سرور است .



**ببخشید طولانی شد،میخواستم تو 2تا پست بنویسم اما ترسیدم دیگه وقت نشه پست بعدی رو بنویسم ;)

**سوالی هست درخدمتم

**اگر احیانا در تعاریف دچار اشتباه شدم حتما برام کامنت بزنید :)

**خب تموم شد امیدوارم فرصت شه بازم، هرچند کوتاه هرچند ناقص، براتون بنویسم ?