thread یا رشته عبارتند از واحد های کلی پردازش وظایف که هر برنامه می تواند تعدادی ترد داشته باشد. هر ترد اولویتی در سیستم دارد و تردهای ایجاد شده توسط یک ترد دیگر، اولویت هم سطح خواهند داشت. در اندروید هر برنامه یک ترد اصلی یا Main thread دارد و وقتی thread جدیدی ایجاد می کنیم پردازش ها جدا از اتفاقات ترد اصلی روی می دهد. اما برای هماهنگ کردن و یا به عنوان مثال بازگشت جواب باید اینکار را بصورت دستی توسط message یا callback مدیریت کنیم.
در این مقاله می خواهیم نحوه ارتباط با این دو روش را برسی کنیم.
message
اصلی ترین راه ارتباط بین تردها پاس دادن پیام است. تردی که قرار است پیغام را دریافت کند باید دسترسی به صف پیغام ها داشته باشد که messageQueue است و خود ترد ساده فاقد این کلاس است.
1 2 3 4 5 6 |
new Thread(new Runnable() { @Override public void run() { doSomething(); } }).start(); |
به شکل thread ساده و بدون messageQueue توجه کنید:
برای افزودن messageQueue از کلاس Looper استفاده می کنیم که messageQueue را برایمان فراهم می کند.
1 2 3 4 5 6 7 8 |
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); doSomething(); Looper.loop(); } }).start(); |
و بدین ترتیب messageQueue برایمان محیا می شود.
حال تردی که می خواهد مسیج ارسال کند نیاز به یک Handler دارد. وظیفه Handler ارسال و پردازش پیغام مربوط به messageQueue ترد ساخته شده اش می باشد. ( همچنین اجرای Runnable که موضوع این آموزش نیست). وقتی یک Handler جدید می سازیم به threadhd ای که درون آن ساخته شده و messageQueue مربوطه متصل می شود و message ها و runnable ها را به messageQueue مربوطه می رساند و یا از روی آن اجرا می کند. در اینجا برای ارسال پیام کافیست که یک هندلر بصورتی تعریف کنیم هردو ترد دسترسی داشته باشند ( بصورت public یا پاس دادن بصورت properties) در یکی توسط آن Messagehvshg ارسال کنیم و در دیگری Message را گرفته و پردازش کنیم.
به مثال ذیل توجه کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
private void testThreadMessaging() { new Thread(new Runnable() { @Override public void run() { Looper.prepare(); handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Toast.makeText(MainActivity.this, "Job finish with ( "+(float) msg.getData().getLong("jobTime")/1000+" ) seconds", Toast.LENGTH_SHORT) .show(); } }; Looper.loop(); } }).start(); new Thread(new Runnable() { @Override public void run() { long jobTime = doSomething(ITERATION_COUNT); Message message = new Message(); Bundle bundle = new Bundle(); bundle.putLong("jobTime",jobTime); message.setData(bundle); handler.sendMessage(message); } }).start(); } |
1 2 3 4 5 6 7 8 9 |
private long doSomething(int iteration) { long startTime = System.currentTimeMillis(); for (int i = 0; i < iteration; i++) { Log.i("mahdi", "run: "+i); } long endTime = System.currentTimeMillis(); return endTime - startTime ; } |
ترد اول بعد از تمام شدن کارش زمان انجام کار را به ترد دوم پاس می دهد. در اینجا handler بصورت public تعریف شده بود.
Callback
در این روش ارتباط از طریق پاس دادن یک اینترفیس انجام می شود. برای اینکه مثال فرق کند ترد دریافت کننده پیام را در Ui thread قرار دادم. ( یعنی ترد جدیدی نساختم و در یک جایی در اکتیویتی تعریف کردم که می دانیم خود اکتیوتی در main thread یا همان Ui thread است).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
private void testThreadCallBack(){ //our receiver thread is main thread callBack = new ThreadCallBack() { @Override public void onMessage(Object o) { Log.i("mahdi", "Job finish with ( "+((Bundle) o).getLong("jobTime")/1000+" ) seconds"); } }; new Thread(new Runnable() { @Override public void run() { long jobTime = doSomething(ITERATION_COUNT); Bundle bundle = new Bundle(); bundle.putLong("jobTime",jobTime); callBack.onMessage(bundle); } }).start(); } interface ThreadCallBack{ void onMessage(Object o); } |
برای درک بهتر کدها را اجرا کنید و نتایج را برسی کنید. در صورتی که سوال یا نکته ای داشتید کامنت کنید.
واااااای …واقعا دمت گرم عالی توضیح دادی خیلی وقت بود نمیتونستم این messageQueueو ارتباطش با handlerوthreadرو درک کنم…واقعا دمت گررررررم
سلام. خوشحالم که برات مفید بوده. 🙂