AsyncTask
برای استفاده از کلاس asyncTask باید یه کلاس جدید بنویسیم و از asyncTask اکستندش کنیم. asyncTask یک کلاس ابسترکت هست و باید حتما متد doInBackground پیاده سازی بشه.
کلاس asyncTask سه تا پارامتر به عنوان جنریک میگیره که مربوط به متد doInBackground هستن که در ادامه بیشتر توضیح میدم.
متد doInBackground در یک ترد جداگونه اجرا میشه. متدهای onPreExecute و onPostExecute هم هستن که با توجه به اسمشون قبل از اجرای متد doInBackground در ترد UI و بعد از اجرای doInBackground در ترد UI اجرا میشن. متد doInBackground خروجیش رو توی ورودی متد onPostExecute قرار میده. برای انتقال نتیجه به اکتیویتی چیکار کنیم؟
دو تا راه هست. یکی استفاده از متد get که خروجی رشته داره و توی try catch قرار میگیره و متعلق به خود کلاس asyncTask هست. روش دوم استفاده از interface هست که من اینو بیشتر ترجیح میدم.
یه اینترفیس مینویسیم و توی کلاس asyncTask یک نمونه ازش تعریف میکنیم. این اینترفیس میتونه توسط اکتیویتی پیاده سازی بشه. برای اطلاعات بیشتر این و این یکی
توی متد doInBackground به UI دسترسی نداریم. ولی برای اینکه یه گزارشی از روند کار داشته باشیم میشه از publishProgress استفاده کرد. جنس ورودی این دومین متغیر جنریک کلاس هست و از نوع varargs می باشد.
حالا باید متد onProgressUpdate رو اووراید کنیم و بگیم مثلا ورودیش رو توی تست ویو نشون بده. ورودیش چیه؟ آفرین، همون که در آرگومان publishProgress در متد doInBackground نوشتیم. ایده publishProgress و onProgressUpdate خیلی جالب بود خوشمان آمد :))
public class MainActivity extends AppCompatActivity {
public TextView txt_show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt_show = findViewById(R.id.txt_show);
new AsyncTaskIntro().execute("task1", "task2", "task3","task4", "task5", "task6");
}
class AsyncTaskIntro extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
txt_show.append("task is starting... \n\n");
}
@Override
protected String doInBackground(String... strings) {
for ( String task: strings) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(task+" is completed.\n");
}
return "done";
}
@Override
protected void onProgressUpdate(String... values) {
txt_show.append(values[0]+"\n");
}
@Override
protected void onPostExecute(String s) {
txt_show.append("task is finished.\n");
}
}
}
خروجی کد بالا:
چجوری از کلاس نیو میکنیم؟
یک شی از کلاسی که asyncTask رو پیاده سازی کرده میسازیم و روی اون execute رو فراخونی میکنیم. هر چی توی ورودی execute قرار بگیره ورودی متد doInBackground خواهد بود. همون طور که مشخصه، ورودی این متد به صورت varargs هست. در این حالت متد doInBackground کارشو به صورت سریال انجام میده. یعنی اگر یک باتن داشتیم و با هر بار کلیک روی آن یک شی از کلاس asyncTask ساخته میشد (شبیه مثال فرادرس) در این صورت ابتدا اولی انجام شده و پس از اتمام آن دومی انجام میشد.
ولی میشه یه کاری کرد که در مثال بالا همه کارها با هم انجام بشن. در این صورت نیو شدن از کلاس asyncTask به صورت زیر خواهد بود:
new AsyncTaskIntro().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "task");
یه حالت دیگه برای پارامتر اول هست:
AsyncTask.SERIAL_EXECUTOR
که همون حالت قبلی یعنی اجرای سریال هست.
پس سه تا پارامتری که کلاس AsyncTask میگیره به ترتیب اینجوریه:
ورودی متد doInBackground
جنس ورودی متد onProgressUpdate
خروجی متد doInBackground
اگر نیازی به استفاده از متد onProgressUpdate نباشه، دومین جنریک رو Void قرار میدن.
این لینک خیلی خوبه و asyncTask های موازی رو با مثال توضیح داده
سلام اونی که برای اجرای Async Task اجباریه کدومه ؟