آموزش برنامه نویسی غیر همزمان در Flutter
در مدل معمولی برنامه نویسی زمانی که ما یک دستور را اجرا میکنیم کامپایلر تا مدت زمان تمام شدن این دستور هیچ کار دیگری انجام نمیدهد.
خب در این زمان اگر دستور ما زمانبر باشه برنامه به اصطلاح فریز میشه و کاربر تا پایان تموم شدن این دستور هیچ کار دیگری نمیتواند انجام دهد.
برای حل این مشکل اکثر زبان های برنامه از برنامه نویسی چند نخی یا مالتی تردینگ استفاده می کنند.
در زبان دارت ما بحث مربوط به مالتی تردینگ را نداریم زیرا این زبان فقط از یک Thread برای اجرا برنامه استفاده می کند.
اما برای حل این مشکل از برنامه نویسی غیر همزمان با استفاده از دستورات کلیدی await, Future میتونیم استفاده کنیم.
آبجکت های Future در واقع نتیجه دستورات اجرا شده هستند که به برنامه برگشت داده می شوند.
برای مثال دانلود فایل کاری زمانبر هست و ما نمیخوایم در این مدت برنامه فریز بشه.
به همین دلیل از Future و await استفاده می کنیم.
زمانی که دانلود فایل به اتمام رسید با استفاده از آبجکت Future میتونیم از این عمل اطلاع پیدا کنیم.
همچنین با استفاده از await به نتیجه Future میتونیم دسترسی داشته باشیم. در بعضی مواقع نیاز هست که یک مقداری برگشت داده شود.
آبجکت های Future کانستراکتور های متنوعی دارند.
کانستراکتور پیشفرض و اولیه Future یک متد async به عنوان پارامتر قبول می کند, زمانی که این متد یک مقدار برگرداند Future عملیات خودش را کامل کرده هست.
Future(() async {…});
اگر بخواهید که وقفه قبل از اجرا متد ایجاد کنید هم میتونید از دستور زیر استفاده کنید.
delayed(Duration)
همچنین اگر نیاز داشته باشید که چندین درخواست همزمان ارسال کنید میتونید از کانستراکتور زیر استفاده کنید تا از نتیجه هر درخواست اطلاع پیدا کنید.
wait(Iterable<Future>)
اگر متد شما هیچ مقداری برنمیگرداند باید متد خودتون و به شکل زیر از نوع void ایجاد کنید.
Future myFunc() async => …
مثال زیر روش های مختلف استفاده از Future و به خوبی نشون میده.
void main() async {
/// Create a Future from the default constructor
await Future(() async {
/// Use the delayed constructor to create a Future that will resolve after x time.
await Future<void>.delayed(Duration(seconds: 2));
print("hello");
});
/// Do not freeze the code
doARequest();
/// Freeze the code
await doARequest();
/// It will not freeze the code because the function does not return an object of type Future
await doARequest2();
/// Freeze the code until the future is completed
final String t = await retrieveStringFromStorage();
final String t2 = await retrieveStringFromStorage2();
/// Will print true !
print(t == t2);
}
Future<void> doARequest() async {
await requestToServer();
}
void doARequest2() async {
await requestToServer();
}
Future<String> retrieveStringFromStorage() async {
final String t = await getStringFromStorage();
return t;
}
/// Is equivalent to
Future<String> retrieveStringFromStorage2() => getStringFromStorage();
اگر میخواهید همزمان با تکمیل شدن درخواست دستورات شما ویو برنامه را آپدیت کنید میتونید از ویجت FutureBuilder کمک بگیرید. برای مثال زمانی که تا دریافت کامل اطلاعات نیاز دارید یک لودینگ به کاربر نمایش دهید.
کلاس Stream
استریم هم مثل Future در برنامه نویسی غیر همزمان نقش مهمی دارد.
قبلا بصورت مختصر در مورد Stream صحبت کردیم در مقاله زیر.
برای کار با استریم ابتدا باید یک آبجکت از کلاس StreamController ایجاد کنید.
این کلاس اجازه کنترل Stream و به شما میدهد. یعنی از طریق StreamController هست که میتونید رویداد های مختلف و در Stream ایجاد کنید.
اما این تمام کار نیست با استفاده از StreamController میتونید State ویجت استریم را چک کنید که در چه وضعیتی قرار دارد.
در فلاتر ما دو نوع استریم داریم که شامل Single-subscription stream و Broadcast stream می باشد.
Single-subscription stream
در این نوع استریم فقط اجازه استفاده به یک کلاینت داده می شود.
در این نوع استریم یک فضای بافر از ایونت ها ساخته می شود تا زمانی که یک کلاینت شروع به گوش دادن به این استریم کند.
و زمانی که کلاینت اتصال خود از استریم را قطع میکند دیگر به این ایونت ها دسترسی نخواهد داشت.
Broadcast stream
این نوع استریم که امکان دسترسی چندین کلاینت به استریم را می دهد. اما هیچ نوع بافری در این نوع استریم وجود ندارد.
import 'dart:async';
void main() {
StreamLife streamLife = StreamLife();
}
class StreamLife {
StreamLife() {
controller2.add('eventBeforeListener');
subscription1 = stream.listen((String value) {
print(value + ' - sub1');
});
subscription2 = stream.listen((String value) {
print(value + ' - sub2');
});
subscription3 = stream2.listen((String value) {
print(value + ' - sub3');
});
launch();
}
final StreamController<String> controller = StreamController<String>.broadcast();
final StreamController<String> controller2 = StreamController<String>();
Stream<String> get stream => controller.stream;
Stream<String> get stream2 => controller2.stream;
StreamSubscription subscription1;
StreamSubscription subscription2;
StreamSubscription subscription3;
Future<void> launch() async {
await Future<void>.delayed(Duration(milliseconds: 100));
controller.add('one');
await Future<void>.delayed(Duration(milliseconds: 100));
controller.add('two');
await Future<void>.delayed(Duration(milliseconds: 100));
subscription1.cancel();
await Future<void>.delayed(Duration(milliseconds: 100));
controller.add('tree');
await Future<void>.delayed(Duration(milliseconds: 100));
subscription2.cancel();
await Future<void>.delayed(Duration(milliseconds: 100));
controller2.add('ttt');
await Future<void>.delayed(Duration(milliseconds: 100));
try {
stream2.listen((String v) {
print(v);
});
}
catch (e) {
/// this will not work because there is already a listener on the stream2! (single subscription)
}
await Future<void>.delayed(Duration(milliseconds: 100));
subscription3.cancel();
}
}
خروجی کد بالا به شکل زیر می باشد.
eventBeforeListtener — sub3
one — sub1
one — sub2
two — sub1
two — sub2
tree — sub2
ttt — sub3
مطالب زیر را حتما مطالعه کنید
آموزش پیاده سازی لینت Lint در برنامه نویسی فلاتر
آموزش الگوی تزریق وابستگی در فلاتر Dependency Injection
کتاب های آموزش برنامه نویسی فلاتر + دانلود PDF
آموزش نصب فلاتر و رفع خطاهای رایج ساخت پروژه + ویدیو
آموزش استفاده از نقشه در فلاتر
آموزش ساخت Navigation Drawer در فلاتر
4 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
بسیار عالی
خیلی خوب و مفید بود
ممنونم
سلام
چرا وقتی کد Stream شما رو کپی میکنم و اجرا میگیرم خطا میده.
Unhandled exception:
Class ‘_Type’ has no instance method ‘call’.
NoSuchMethodError: method not found: ‘call’
Receiver: Type: class ‘StreamLife’
Arguments: []
#۰ Object._noSuchMethod (dart:core-patch/object_patch.dart:42)
#۱ Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
#۲ main (file:///home/cg/root/4445237/main.dart:6:37)
#۳ _startIsolate. (dart:isolate-patch/isolate_patch.dart:255)
#۴ _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:142)