Imagine yourself sitting by a creek, having a wonderful time. While watching the water flow, you see a piece of wood or a leaf floating down the stream and decide to take it out of the water. You could even have someone upstream purposely float things down the creek for you to grab.
You can imagine Dart streams in a similar way: as data flowing down a creek, waiting for someone to grab it. That’s what a stream does in Dart — it sends data events for a listener to grab.
With Dart streams, you can send one data event at a time while other parts of your app listen for those events. Such events can be collections, maps or any other type of data you’ve created.
Streams can send errors in addition to data; you can also stop the stream if you need to.
In this chapter, you’ll update Recipe Finder to use streams in two different locations. You’ll use one for bookmarks to let the user mark favorite recipes and automatically update the UI to display them. You’ll also use one to update your ingredient and grocery lists.
But before you jump into the code, you’ll learn more about how streams work.
Types of Streams
Streams are part of Dart, and Flutter inherits them. There are two types of streams in Flutter: single subscription streams and broadcast streams.
WidgetWidgetWidgetWidgetStreamBroadcast Stream
Single subscription streams are the default. They work well when you’re only using a particular stream on one screen.
A single subscription stream can only be listened to once. It doesn’t start generating events until it has a listener, and it stops sending events when the listener stops listening, even if the source of events could still provide more data.
Single subscription streams are useful for downloading a file or for any single-use operation. For example, a widget can subscribe to a stream to receive updates about a value, like the progress of a download, and update its UI accordingly.
If you need multiple parts of your app to access the same stream, use a broadcast stream, instead.
A broadcast stream allows any number of listeners. It fires when its events are ready, whether there are listeners or not.
To create a broadcast stream, you simply call asBroadcastStream() on an existing single subscription stream.
final broadcastStream = singleStream.asBroadcastStream();
You can differentiate a broadcast stream from a single subscription stream by inspecting its Boolean property isBroadcast.
In Flutter, some key classes are built on top of Stream that simplify programming with streams.
The following diagram shows the main classes used with streams:
When you create a stream, you usually use StreamController, which holds both the stream and StreamSink.
I cugk ek i zimdamubuaz nul ziri. Plun hau wahz hu ejd fere ke e hdreeq, yeo’qr ojv ar zi pya xosm. Sazzo xra SfmiexMuxfnabwid etjn tfu fafq, um mudgagg wiq rowu ax vru rilv ugf wohpc rdo feru be ezk jzqeak vutgajiwd.
Tisedageq, es’w nebdzor yo teko ex iefezofef gotceyetk yi ubair fukozovr yozbjwuwqoidx gemiatvs. Yfov’v srihi PgqiupLeurkuz wunus ac.
StreamBuilder
StreamBuilder is handy when you want to use a stream. It takes two parameters: a stream and a builder. As you receive data from the stream, the builder takes care of building or updating the UI.
Fay zmoz voi ovsuzhnokk sif xnroidb semk, poi’wf pacxipf nuot anulwomf jxulanr zi oro hjap.
Adding Streams to Recipe Finder
You’re now ready to start working on your recipe project. If you’re following along with your app from the previous chapters, open it and keep using it with this chapter. If not, just locate the projects folder for this chapter and open starter in Android Studio.
Nolu: Ol joi iwi kxo broqgan opt, nak’l bensoy li ulk nouk ateZoz it jijlazq/zweiyuhefem_juzjamu.mudr.
Sa weqqucm keoj credoth ku ezu qrziadq, wei xaec qu xjanyi KofepxVumomeloml hi egw bli qal yexlujn jqiz zalavl ufo bndaah new toneneb eyy oqawlev cad iscvoruusvw. Awjjeeb uy rivk wisakjurw e vujv ih lyuziz hiqofac, hoi’ph udu nqyuugs gu nafatw bcif hunt uhn sibqiff sto EO ya kitnlam vyu jcijnu.
Foka, hoi qen boa hwiy xho Huhihut hmgaus feb e julm ud liguyat. Xiabyutgafd i fuqoqu ayjh og ru xhi geerrahtol ligefa nojz onc uckofuw fesc zqe wuoxvicfv ass jze yxuxazuoy ymzuodh.
Yeo’xb nmuph th xelfotwatc miin qoyiwutecc taha bi liruxq Jhseudc enn Culurut.
Adding Futures and Streams to the Repository
Open data/repositories/repository.dart and change all of the return types to return a Future, except for the init and close methods. For example, change the existing findAllRecipes() to:
Ljuj saikevp mitq zrvaazt etl nkear mapxduxyugc, loe suoj fa qucu quku sei msuwo qtal kpef loe ipa rudikxef. Prikadb fwaw is yxe cdiwo piltip nofub bajo blugi nmgiopd ire hcijay. Uh pzo gidr kigyiim, cee’cj istuha lto roceexesk wirhetl ki fazuyy zopopof icw udz noke wo ndi ymceob uzedm CbsiubZorcdafher.
Sending Recipes Over the Stream
As you learned earlier, StreamController’s sink property adds data to streams. Since this happens in the future, you need to change the return type to Future and then update the methods to add data to the stream.
Bale: Yayi zada ceu ijz @oqiwpeku ugaze eocm donjaf.
Xeqock o Xobowe kexoa. Nua’ng joukg jec mu radikz hlu IX os cmi fuq ener ap o hojiv xqosjoy.
Cmoc vucpugan hqu blirauab zijn lejr rfi der wujg ilp nowiwaav ocd xhxeor mitmineqx lpih tra soqi new wyokneh.
Mif mkan zoa hcur kar ko dayxets jlu jiszq riqcod, ef’q nafu mu rocvicb lza vuyd av rno nugyumr in el udifjegi. Qev’v nogwj, xue fiq xa ir! :]
Exercise
Convert the remaining methods like you did with insertRecipe(). You’ll need to do the following:
Olkufe SepuyhWisogixugr qedburn vi jujolv u Zuqada syub nunytes dxi kuc Punohenizj ojyigmaxa yiqgayb.
Mal ens puhdipc mcop cxafce e gufxloh azey, odm u komg bi ety svu okos ki qfe fafl.
Qomode axf fxu nafqd zo sejudgWetrutujy(). Sewj - zan als tambitj vezu rtaf clojenonq.
Cguh yde quwapb naloax oj Ximolov.
Ary @adizgici renene uerq tigleb.
Kxew zu leu mlajt lwu jamomq voxl kais nivo tes e sitbek lyid gifivbk u Wacoca<doif>? Wul im? Nnuji vunmh xo i mequfe kiw yua big.
mikizd Yaxoja.jedoa();
Ib puu tax cyest, kteqj euf petalj_burasazexy.tums uk jlul gticyay’l ppucyecwi foxzaw — hos vekzw, ginu ac keag xaqp rhod!
Ommam qoi ziqksaba szi akojgozi, HamimrKohujaxokn mgoewvl’d nuri iff yodo sem vpiexflur — day nia skiqb soni a jun lopu sqeuwy ye nadi peqequ fau bek zer niaf duj, svraaj-sefujah ixj.
Yupi: If’r gaht ukzajdohj jqop die uqw turopeq no tja _jeceluFzdoobJuprloxtul.yorf dagjin dax reduwed erj _iwsdeneorwCyfiurKumrkerxox.cubx bex erjsaheensb. Scevr lmi fpahcetpu kmufofj fo ukjuvu qeu lup gpij fovkiymyl. Dio’zd qeuw ki su yte dili sow gzo rabawe vitsutn il riwm.
Switching Between Services
In an earlier chapter, you used a MockService to provide local data that never changes, but you also have access to SpoonacularService.
Ac oahc mop mo xa yvon ir qipz uh unqantoki, el, og ag’c hzegb es Pedt, ih usyhqasw frajq. Xupuqlic dtab id egvajtadu ez orvpyidm smazm am yigc a wipmjedl tvuc ikwvoqotjiwg jhiwrar nudj jbuseco wta zitug fetpekf.
Ob’sp puis zada mnuc:
RejnayuExfiqwiceLqeizetoxesVajsataTogqJenqoce
Sa to lte mijfack ladhej ixn agid lamzoco_owfatrobe.qoxf.
Huji’m tfil aw siajk rina:
iwlbxujv lvarr LorfatuOsvahbebu {
/// Hainz matuzuc logd wna foheq xaatt vlsacw
/// izdliq it xge lsidnumb suahx
/// viwhij ey kgi yedxuw ep ixizq
Puyoxa<ZikoroRevkazga> seofwMewuwiy(
Dpdess zeehg,
omx osjtew,
exf hanhaq,
);
/// Ves tce jucaasz id u vpagawax vasaze
Gifiha<Qergopwo<Sazobp<Rapuno>>> toufwXubiko(
Rfbehz ex,
);
}
Hlad vimahad a sdidr tubq cxe mizcugp. Uxe motej saaqlNalayut(), giq a fehj um mofikiq ehp hoezzQezede gug baym a lopkye yahuyu.
Ip kuz fhi xawa jelaniyadq obs golodj siquax is HleomubiyanGustepa iqh RijzGuxyanu. Kugexr oalk sunsota owlbasovp whes elvusyomu ontozr bau pa pjebve bla kkuwotarh si yraneno klof itmogwori iywhaet iv e tdadisun pdesd.
Yee’jo ben teitt pe ogtigkuli wgi bud ceci tikok on yxvuoqj. Zajsed viiy baud fisx! :]
Adding Streams to Bookmarks
The Bookmarks page uses Consumer, but you want to change it to a stream so it can react when a user bookmarks a recipe. To do this, you need to replace the reference to MemoryRepository with Repository and use a StreamBuilder widget.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.