مشخصات پروژه
-
760
-
0.0
-
12437
-
0
-
1
معرفی و کاربرد Thread در اندروید
Thread چیست؟ برای افزایش سرعت و همچنین بهینه سازی برنامه می توانیم از برنامه نویسی چند نخی « Thread » استفاده نماییم. با این کار می توانیم وظایف برنام را به چند قسمت تقسیم و به طور همزمان انجام بدهیم تا سرعت بالاتری برای برنامه رقم بزنیم.
دوره آموزش اندروید
دوره آموزش برنامه نویسی اندروید
با عرض سلام و خسته نباشید به شما دانشجویان محترم آموزشگاه تحلیلگر داده ها. در این مقاله قصد داریم بحث بسیار مهم Thread را برای شما دانشجویان توضیح دهیم.
اهداف پروژه :
در این مقاله ما قصد داریم مطالب زیر را برای شما شرح دهیم:
معرفی و کاربرد Thread
انجام یک مثال کوچک
Thread چیست؟
برای افزایش سرعت و همچنین بهینه سازی برنامه می توانیم از برنامه نویسی چند نخی « Thread » استفاده نماییم. با این کار می توانیم وظایف برنام را به چند قسمت تقسیم و به طور همزمان انجام بدهیم تا سرعت بالاتری برای برنامه رقم بزنیم. برنامه نویسی چند نخی یکی از اساسی ترین و مهمترین ارکان برنامه نویسی می باشد که متأسفانه حتی بسیاری از برنامه نویسان حرفه ای نیز آنرا نادیده می گیرند. چرا که با وجود سرعت های بالای CPU در سخت افزارهای PC و Notebook نیاز به استفاده از Thread ها به چشم نمی آید اما یکی از بزرگترین دلایل وجود Hang و در نتیجه Crash ها عدم توجه به این تکنیک برنامه نویسی می باشد.
در دستگاه های ضعیف تر نظیر Smart Phone ها استفاده از Thread ها بسیار واجب و ضروری می باشد و حتی برای انجام هر عمل کم زمانبر نیز استفاده از Thread ها اکیداً توصیه می گردد.
اهم خواص Thread ها عبارتند از:
Thread ها به تنهایی وجود ندارند و باید Process ای د ربرگیرنده آنها باشد.
Thread های هم والد « هم Process » از یک Memory مشترک استفاده می نمایند که آن نیز Memory اشغال شونده توسط Process آنها می باشد.
Thread ها چه هم والد، چه غیر هم والد دارای Stack های جدا هستند.
با خاتمه یک Thread تأثیری به سایر Thread ها وارد نمی گردد.
Thread ها دیگر نمی توانند در برگیرنده Thread دیگری باشند.
Prosses چیست؟
بطور کلی و عام، یک Process عبارتست از یک قطعه برنامه در حال اجرا، اما با ذکر مثال عبارتست از یک نرم افزار، یک بازی، یک سرویس و مشابه اینها. هر چند که هر کدام از مثال های ذکر شده می تواند شامل چندین Process باشد اما غالبا در بسیاری از شرایط
تعداد آن فقط یکی می باشد.
با زدن کلید Ctrl+Alt+Delete در ویندوز و رفتن بهTask Manager در تبProcesses ، ما لیستی از پروسس های اجرا شده در سیستم عامل ویندوز را در لحظه اجرا می بینیم. بعضی از آنها نرم افزارهای ما هستند، بعضی دیگر نرم افزارهای سیستمی، بعضی سرویس و ... می باشند. در این لیست ممکن است چندینProcess به یکدیگر متصل شوند که همانطور که گفته شد غالبا اینگونه نیست.
برای ساده تر شدن مفهوم اینگونه می گوییم که یک نرم افزار، بازی یا سرویس در سیستم عامل اندروید فقط یک Process می باشد.
اهم خواص Process ها عبارتند از:
Process های متفاوت از Memory های متفاوتی استفاده می نمایند.
Process های متفاوت از هر نظر مستقل از یکدیگر عمل می نمایند.
Process ها می توانند شامل یک و یا بیشتر Thread باشند.
با خاتمه یک Process، تمامی Thread های آن نیز به ناگاه خاتمه می یابند.
Process ها دارای Stack نیستند و در ساده ترین شرایط تنها Thread آنها دارای Stack می باشد.
Stack چیست؟
به طور کل Stack محلی از حافظه است که data های ارسالی به آن بصورت LIFO - Last In First Out ذخیره می گردد. اما در مورد بحث کنونی ما فضایی « منحصر به Thread » از حافظه می باشد که در اختیار Thread مربوطه قرار گرفته و نتایج و اطلاعات Function های در حال اجرا در آنجا ذخیره می گردد. بنابراین هر Thread با توجه به Stack خود می داند که خط کنونی برنامه در حال اجرا، از کجا فراخوانی شده و قرار است به کجا بازگردد. یعنی اگر Function های متوالی اجرا گردند، تا زمانی که از آن Function ها بازگشت داده نگردد، اطلاعات مربوط به آن Function از Stack حذف نمی گردد و با بازگشت از آن Function این اطلاعات در اختیار Function صدا زننده قرار گرفته و سپس از Stack پاک خواهد شد.
نحوه اجرای یک برنامه
ابتدا یک Process که حتما یک Thread دارد ایجاد شده و Thread شروع به اجرای دستور العمل های خود می نماید، اگر نیاز باشد که Thread های دیگری تعریف گردد، توسط این Thread تعریف شده و دستور اجرای آنها داده می گردد اما والد آنها Thread اجرا کننده نیست بلکه Process است. در این شرایط بهThread اصلی که در بدو پیدایش Process وجود داشته است Main Thread می گوییم. در برنامه نویسی اندروید به آن UI Thread نیز گفته می شود.. علت این نامگذاری این است که هر گونه عملی بر روی UI حتماً حتماً می بایست از روی این Thread اجرا گردد.
پس در اندروید Main Thread = UI Thread
سایر Thread های ایجاد شده نیز به موازات سایر Thread ها و حتی Thread اصلی شروع به فعالیت کرده و دستور العمل های مربوط به خود را اجرا می نمایند.
اگر دستگاه مورد اجرا دارای یک CPU باشد، چون یک CPU فقط توان اجرای یک دستور را در هر لحظه داراست، از Thread ای به Thread دیگر جهش می نماید و به هر Thread سری می زند تا دستور العمل هایش را اجرا نماید، بنابراین اجرای آن موازی به نظر می رسد. اما اگر دستگاه مورد اجرا دارای بیش از یک CPU باشد، اجرای Thread ها بین CPU ها توزیع می گردد و همزمانی اجرا معنی نزدیک تری به واقعیت پیدا می نماید، چون چند CPU به معنای واقعی می تواند چند دستور را همزمان اجرا نمایند.
Threadها چرا استفاده می گردند؟
از آنجاییکه پاسخ به ورودی های کاربر « استفاده کننده نرم افزار یا بازی » نیازمند سرعت است تا نرمی در نرم افزار احساس گردد، در غیر این شرایط خواص کیفی نرم افزار یعنی stable « پایدار » و smooth « نرم » از بین خواهد رفت. شاید بارها با پیام Not Responding در ویندوز مواجه شده باشید که علت برنامه نویسی ضعیف آن نرم افزار است. پس هر عملی که نیاز به پردازش متوسط به بالا را دارد حتما در Thread دیگری قرار داده و اجرا خواهیم نمود که Main Thread نسبتاً آزاد باشد و آماده پاسخگویی به درخواست های کاربر و نمایش اطلاعات به کاربر باشد.
روش های استفاده از Thread
برنامه نویسی Thread ها یا اصطلاحا Concurrent Programming بسیار پیچیده می باشد و تکنیک های زیادی دارد. با توجه به این که در این موضوع چندین تألیف حدودا 1000 صفحه ای موجود است، انتظار نداریم حتی 5% آنرا هم بشناسیم. لذا به دو تا از ساده ترین و پرکاربرد ترین روش های استفاده از این تکنیک ها در برنامه نویسی اندروید که در شرایط حتی پیچیده نیز مشکل ما را حل خواهند نمود اکتفا خواهیم نمود.
آن دو تکنیک عبارتند از :
Handler
Handler ما را قادر به افزودن پیام به رشته می سازد که آن را ایجاد کرده و ما را قادر می سازد تا برخی از برنامه های اجرایی را به منظور اجرا در آینده برنامه ریزی نماییم.
Handler مربوط به رشته اصلی برنامه می باشد. Handler پیام ها و برنامه های اجرایی و پیام های ارسال شده از رشته ها را به رشته برنامه اصلی مدیریت و برنامه ریزی می نماید.
اگر چندین فعالیت مکرر نظیر دانلود چندین عکس نشان داده شده در ImageView را انجام دهیم، از صف امور به همراه Handler استفاده می نماییم.
دو استفاده اصلی برای Handler وجود دارند. اولین مورد برنامه ریزی پیام ها و برنامه های قابل اجرا در آینده می باشد و دومین عامل صف بندی یک اقدام به منظور اجرا بر روی رشته ای دیگر می باشد.
برنامه ریزی پیام ها با استفاده از روش هایی نظیر post(Runnable)، postAtTime(Runnable, long)، postDelayed(Runnable,long)، sendEmptyMessage(int)، sendMessage(Message)، sendMessageAtTime(Message, long)، و sendMessageDelayed(Message, long) انجام می گیرد.
زمانی که فرایندی برای برنامه ما ایجاد می گردد، رشته اصلی به اجرای پیامی که از بخش های اصلی محافظت می نماید (فعالیت ها، دریافت کننده های پیام) اختصاص داده می شود.
ما می توانیم رشته های خود را ایجاد کرده و با رشته اصلی برنامه با استفاده از Handler در ارتباط باشیم.
AsyncTask
AsyncTask ما را بدون دستکاری رشته ها قادر به اجرای چند رشته می سازد. AsyncTask روش های جدیدی را فراهم می آورد که انجام اقدامات پس زمینه را تسهیل کرده و نتایج را به رشته رابط کاربری انتقال می دهند.
اگر ما اقدامی مربوط به رابط کاربری نظیر دانلود داده ها برای نمایش در یک فهرست را انجام می دهیم، از AsyncTask استفاده خواهیم نمود.
AsyncTasks می بایست برای اقدامات کوتاه (چند ثانیه ای) به کار برده شوند.
یک اقدام ناهمگن توسط سه نوع کلی تعریف می گردد که عبارتند از Params، Progress و Resulg و 4 مرحله که onPreExecute, doInBackground, onProgressUpdate and onPostExecute نام دارند.
در onPreExecute ما می توانیم کد را تعریف نماییم که می بایست قبل از آغاز پردازش اجرا گردد.
در doInBackground ما کدی را داریم که می بایست در پس زمینه اجرا گردد. در اینجا در doInBackground ما می توانیم نتایج را چندین بار به رشته رویداد با استفاده از روش publishProgress() ارسال نماییم تا فرایند های پس زمینه ای که به اتمام رسیده اند را اعلام نماییم.
onProgressUpdate() به روز رسانی های پیشرفت را از روش doInBackground را دریافت می نماید که از طریق روش publishProgress منتشر می گردد و این روش می تواند از این پیشرفت برای ارتقای رشته رویداد ها استفاده نماید.
روش onPostExecute() نتایج ارائه شده توسط doInBackground را مدیریت می نماید.
روش های کلی استفاده شده به شرح زیر می باشند:
Params، نوع پارامترهایی که در حین اجرا ارسال می گردند.
Progress، نوع واحدهای پیشرفت که در حین محاسبات پس زمینه منتشر می گردند.
Result، نوع نتایج محاسبات پس زمینه
اگر AsyncTask از هیچ نوعی استفاده ننماید، در این صورت آن را نوع Void می نامند.
AsyncTask در حال اجرا را می توان با استفاده از روش cancel(Boolean) متوقف نمود.
بزرگترین مشکل استفاده از Thread ها
از آنجاییکه Thread های هم والد همگی از یک Memory مشترک استفاده می نمایند، پس تغییر همزمان این Memory تنها مشکل اصلی استفاده از Thread ها است. به دو مثال رایج از خطاهای ناشی از Thread توجه نمایید:
بطور مثال اگر یک Thread همزمان دارد یک instance از کلاس را تغییر می دهد « می نویسد » و Thread دیگر سعی در خواندن آن داشته باشد، اتفاقات ناگواری پیش خواهد آمد. در این شرایط حتی نیاز است چندین Design Pattern مناسب پیاده سازی گردد.
همچنین اگر یک Thread مقداری را تغییر داد و بعد از آن سعی در خواندن آن داشت، ممکن است به داده درستی نرسد. چون در حد فاصل بین نوشتن و خواندن توسط این Thread ممکن است Thread دیگری آنرا تغییر داده باشد.
بنابراین در برنامه نویسی Thread ها دیباگ کردن بسیار بسیار دشوار و گاه غیرممکن است، لذا بهتر است چیزی ننویسیم که باگ داشته باشد تا اینکه سعی در دیباگ آن داشته باشیم.
در زیر نیز یک نمونه Thread از نوع Handler ایجاد شده است. (شکل 1)
شکل 1
در کد بالا پس از 4 ثانیه « 4000 میلی ثانیه » ، اکتیویتی جاری را با استفاده از کد finish() می بندیم و با استفاده از دستور Intent اکتیویتی SecondActivity را اجرا می نماییم.
در اینجا کار ما به اتمام میرسد. امیدواریم نهایت استفاده از این مقاله را برده باشید.
شاد و پیروز باشید.