ورود و عضویت
0
سبد خرید شما خالی است
0
سبد خرید شما خالی است

نحوه استفاده از RxDart به همراه الگوی بلاک در فلاتر

0 دیدگاه

درباره برنامه نویسی Reactive احتمالا تا به حال زیاد شنیده اید.

یکی از روش های نوشتن برنامه های Reactive استفاده از کتابخانه های خانواده ReactiveX می باشد که برای فلاتر نسخه RxDart استفاده می شود.

خود زبان دارت چند پکیج مختلف برای کار کردن با استریم ها دارد که میتونیم اول این پکیج ها و بررسی کنیم.

استریم Stream در فلاتر چیست؟

استریم ها مجموعه شناوری از دیتا و رویداد ها هستند که میتونید به تغییرات آنها گوش دهید.

برای مثال اگر با ویجت StreamBuilder در فلاتر کار کنید میبینید که این ویجت با متصل شدن به یک استریم خودش و با آخرین تغییرات دیتا و رویداد بروز رسانی میکنید و دوباره از اول میسازد.

درباره الگوی bloc در فلاتر هم قبلا آموزشی و داشتیم میتونید مطالعه کنید.

کتابخانه RxDart

در حال حاضر پکیح RxDart نسخه 0.23 منتشر شده و بر اساس همین نسخه هم کار میکنیم.

قبل از شروع درباره یک سری از ویژگی ها آن خوبه که صحبت کنیم.

Observable class

Observable یا قابلیت مشاهده شدن به ما این امکان و میده تا یک نوتیفیکیشن به ویجتی که در حال مشاده کردن یا observing هست ارسال کنیم تا از تغییرات با خبر شود و کاری که نیاز هست را انجام دهد.

کلاس Observable هم از کلاس استریم ارث بری میکند که امکانات زیر و در اختیارمون میذاره:

  • تمام متد های تعریف شده در کلاس استریم در Observable هم قابل دسترس است.
  • همه Observable ها به هر متد و API ایی که به عنوان ورودی یک استریم را میپذیرد میتوان پاس داد.

PublishSubject class

این موضوع خیلی سادست و Subject در واقع اجازه میده تا رویداد هایی مثل خطا, اطلاعات و پایان کار را به listener ارسال کنیم.

PublishSubject<int> subject = new PublishSubject<int>();

/*this listener below will print every integer added to the subject: 1, 2, 3, ...*/
subject.stream.listen(print);
subject.add(1);
subject.add(2);

/*but this listener below will print only the integer added after his initialization: 3, .../*
subject.stream.listen(print);
subject.add(3);

BehaviorSubject class

این ویژگی ها بسیار شبیه به قبلی هست و به ما اجازه میده تا رویداد هایی مثل خطا, اطلاعات و پایان کار را به listener ارسال کنیم اما آخرین آیتمی که در Subject اضافه شده است به تمام listeners  ها ارسال می شود.

BehaviorSubject<int> subject = new BehaviorSubject<int>();
subject.stream.listen(print); // prints 1,2,3 
subject.add(1);
subject.add(2);
subject.add(3);

subject.stream.listen(print); // prints 3

ReplaySubject class

ReplaySubject هم دقیقا کار نمونه های قبلی و انجام میده اما به یک روش دیگر.

زمانی که آیتم ها درون Subject اضافه می شوند ابتدا ذخیره می شوند و سپس هر زمان که یک استریم شروع به گوش دادن کرد آیتم ها به listener ارسال می شوند.

ReplaySubject<int> subject = new ReplaySubject<int>();

subject.add(1);
subject.add(2);
subject.add(3);

subject.stream.listen(print); // prints 1, 2, 3

برای شروع کار و تمرین کردن RxDart  به طورعملی بهترین کار استفاده از پروژه پیش فرض خود Flutter می باشد.

به همین خاطر یک پروژه جدید بسازید و پکیج RxDart را هم به عنوان اضافه کنید.

در این پروژه که خودش تابع اضافه کردن مقدار به یک عدد و از اول دارد ما میخوایم که عمل کم کردن از عدد را پیاده سازی کنیم.

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void _decrementCounter() {
    setState(() {
      _counter--;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text('You have pushed the button this many times:',),
            new Text('$_counter', style: Theme.of(context).textTheme.display1),
          ],
        ),
      ),
      floatingActionButton: new Column(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
        new Padding(padding: EdgeInsets.only(bottom: 10), child:
          new FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: new Icon(Icons.add),
          )
        ),
        new FloatingActionButton(
          onPressed: _decrementCounter,
          tooltip: 'Decrement',
          child: new Icon(Icons.remove),
        ),
      ])
    );
  }
}

همونجور که کد بالا و میبینید دو بخش منطقی در برنامه داریم که متد های اضافه و کم کردن عدد هستند.

اما هنوز الگوی Bloc و پیاده سازی نکردیم ولی کد به شکل کامل و درست کار میکنه.

حالا فرض کنید خواستیم تغییراتی در کد اعمال کنیم مثلا به جای کم و زیاد کردن به اندازه یک واحد بیایم و دو واحد تغییرات اعمال کنیم.

خب این کار ساده هست اما اگر پروژه واقعی بود و تغییراتی که میخواستیم زیاد بود خیلی سخت میشد.

نکته بعدی اینکه اعمال تغییرات در این بخش با طراحی رابط کاربری کاری ندارد پس بهتره که بخش منطقی برنامه و از رابط کاربری جدا کنیم.

import 'package:rxdart/rxdart.dart';

class CounterBloc {

  int initialCount = 0; //if the data is not passed by paramether it initializes with 0
  BehaviorSubject<int> _subjectCounter;

  CounterBloc({this.initialCount}){
   _subjectCounter = new BehaviorSubject<int>.seeded(this.initialCount); //initializes the subject with element already
  }

  Observable<int> get counterObservable => _subjectCounter.stream; 

  void increment(){
    initialCount++;
    _subjectCounter.sink.add(initialCount);
  }

  void decrement(){
    initialCount--;
    _subjectCounter.sink.add(initialCount);
  }

  void dispose(){
    _subjectCounter.close();
  }
  
}

در توضیحات کد بالا, ابتدا ما یک کلاس به نام CounterBloc  ساختیم که کتابخانه rxdart  را ایمپورت کرده است.

در این لحظه نیاز داریم تا مقدار اولیه برای شروع شمارش و به دست بیاریم که بهش initialCount میگیم.

برای پیاده سازی این مثال من از BehaviorSubeject استفاده میکنم و زمانی که ویجت به یک گوش دهنده Subject تبدیل شد اولین مقدار و از طریق استریم ارسال میکنم تا initialCount مقداردهی شود در متد سازنده کلاس.

ما یک متد به اسم counterObeservable نیز داریم.

این متد یک Observable از نوع Subject برمیگرداند.

در واقع این آبجکتی است که در زمان تغییر اطلاعات به ویجت ارسال می شود.

import 'package:flutter/material.dart';
import 'package:bloc_example/bloc/CounterBloc.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  CounterBloc _counterBloc = new CounterBloc(initialCount: 0);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text('You have pushed the button this many times:'),
            new StreamBuilder(stream: _counterBloc.counterObservable, builder: (context, AsyncSnapshot<int> snapshot){
              return new Text('${snapshot.data}', style: Theme.of(context).textTheme.display1);
            })
          ],
        ),
      ),
      floatingActionButton: new Column(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
        new Padding(padding: EdgeInsets.only(bottom: 10), child:
          new FloatingActionButton(
            onPressed: _counterBloc.increment,
            tooltip: 'Increment',
            child: new Icon(Icons.add),
          )
        ),
        new FloatingActionButton(
          onPressed: _counterBloc.decrement,
          tooltip: 'Decrement',
          child: new Icon(Icons.remove),
        ),
      ])
    );
  }

  @override
  void dispose() {
    _counterBloc.dispose();
    super.dispose();
  }
  
}

مقدار initialCount و برابر صفر قرار دادیم.

متد های increment  و decrement  رو هم پاک کردیم.

زمانی که هر دوتا FloatingActionButton کلیک شوند متد correspondent صدا زده می شود.

از یک StreamBuilder  هم برای نمایش ویجت ها استفاده میکنیم.

آموزش RxDart

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Hesam
20 فوریه 2020
آموزش فارسی فلاتر
آموزش فارسی flutter