در برنامه نویسی از واژههای Synchronous(همزمان) و Asynchronous(غیر همزمان) خیلی استفاده میشود. شاید معنی این دو واژه خیلی به مفهومی که دارند نزدیک نباشد.
مثلا زمانی که کدهای شما به صورت همزمان نوشته میشوند یعنی به ترتیب و پشت هم اجرا میشوند و این هیچ ربطی به همزمان اجرا شدن آنها ندارد. مثلا کد زیر را در نظر بگیرید:
int a = 20; System.out.println(a); a = 30; System.out.println(a); a = 40; System.out.println(a);
خروجی به ترتیب 20، 30 و 40 خواهد بود و همیشه این خطوط به ترتیب اجرا میشوند.
اما بعضی وقتها نیاز است تا کدها به شکل غیر همزمان نوشته شوند. مثلا فرض کنید میخواهید زمان را از اینترنت لود کنید و به کاربر نشان دهید. فرآیند لود کردن زمان از اینترنت یک فرآیند زمان بر است. پس سعی میکنیم این فرآیند را در ترد دیگری اجرا کنیم (یا مجبور به این کار هستیم؛ سیستم عامل اندروید به ما اجازه نمیدهد این کار را در ترد ui انجام دهیم).
String currentTime = "" currentTime = loadCurrentTimeFromInternet(); System.out.println(currentTime);
تابع loadCurrentTimeFromInternet وظیفه گرفتن زمان از اینترنت را داراست. این فرآیند زمان بر است. اگر کد ما مانند مثال به صورت همزمان نوشته شده باشد، برنامه در این خط متوقف میشود تا زمان از اینترنت لود شود و سپس خط پرینت اجرا خواهد شد.
تا اینجا متوجه شدیم چرا باید برای کارهایی که سرعت پایین تری دارند از برنامه نویسی غیر همزمان استفاده کنیم. اما مشکلی که این نوع برنامه نویسی ایجاد میکند این است که هیچ تضمینی وجود ندارد که کدهای شما بر ترتیب اجرا شوند.
String currentTime = "0" AsynchronousClass asynchronousClass = new AsynchronousClass(); currentTime = asynchronousClass.loadCurrentTimeFromInternet(); System.out.println(currentTime);
در کد بالا تابع loadCurrentTimeFromInternet در ترد دیگری اجرا میشود. چون لود کردن زمان از اینترنت زمانبر است پس حتما قبل از اینکه کار این متد تمام شود و مقدار return شود خط print انجام میشود و قابل حدس است که ما در کنسول زمان را صفر میبینیم.
یکی از راه حل ها استفاده از callback است.
تابع کالبک تابعی است که:
1) توسط تابع دیگری صدا زده میشود.
2) زمانی صدا زده میشود که کار تابع اول به اتمام رسیده باشد.
پس در برنامه نویسی غیر همزمان میتوانیم با استفاده از کالبک پس از اتمام کاری که در ترد دیگر انجام میشود،کار دیگری را انجام دهیم. پس در نتیجه یک فرآیند غیر متوالی را به یک فرآیند متوالی تبدیل کرده ایم.
برای پیاده سازی یک کالبک نیاز است تا کارهای زیر را انجام دهیم:
1) تعریف متدی که میخواهیم بعد از اتمام فرآیند صدا زده شود در یک اینترفیس
2) پیادهسازی اینترفیس مرحله قبل در کلاسی که میخواهیم پس از اتمام اجرا شود.
3) تعریف یک رفرنس از اینترفیس در کلاسی که این فرآیند غیر همزمان را اجرا میکند.
4) صدا زدن متد در اینترفیس، توسط کلاسی که فرآیند غیر همزمان را اجرا میکند.
پس برای ساخت کالبک مراحل را به ترتیب طی میکنیم:
public interface Callback { void methodToCallBack(String time); }
ساخت یک اینترفیس
public class MainActivity extends AppCompatActivity implements Callback { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AsynchronousClass asynchronousClass = new AsynchronousClass(); asynchronousClass.loadCurrentTimeFromInternet(); } @Override public void methodToCallBack(String time) { System.out.println(time); } }
پیاده سازی این اینترفیس در کلاس main
public class AsynchronousClass { private Callback callback; public AsynchronousClass(Callback callback) { this.callback = callback; } }
تعریف یک رفرنس از اینترفیس در کلاسی که این فرآیند غیر همزمان را اجرا میکند.
public class AsynchronousClass { private Callback callback; public AsynchronousClass(Callback callback) { this.callback = callback; } public void loadCurrentTimeFromInternet(){ String time = "" Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { String time = "18:30" callback.methodToCallBack(time); // صدا زدن متد } }, 2000);// ایجاد تاخیر دو ثانیه ای برای شبیه سازی } }
صدا زدن متد در اینترفیس، توسط کلاسی که فرآیند غیر همزمان را اجرا میکند.
در نهایت هر زمان که دیتا از اینترنت لود شد یک متد فراخوانی میشود که کارش نمایش زمان است و به این صورت ما تونستیم با استفاده از اینترفیس یک فرآیند غیر ترتیبی را به یک فرآیند ترتیبی تبدیل کنیم.