Flutter
...
Data Objects
Guida tecnica ai tipi di dati Parse con Flutter
18 min
questa guida introduce i tipi di dati parse in flutter, utilizzando esempi dal main dart file l'archiviazione dei dati parse ruota attorno a parseobject, che contiene coppie chiave valore di dati compatibili con json, rendendolo senza schema ciò significa che puoi memorizzare qualsiasi dato senza definire uno schema in anticipo puoi impostare qualsiasi coppia chiave valore desideri, e il nostro backend le memorizzerà ad esempio, supponiamo che tu stia tracciando i punteggi più alti per un gioco un singolo oggetto parse potrebbe contenere ti suggeriamo di nameyourclasseslikethis e nameyourkeyslikethis per migliorare la leggibilità e la manutenibilità del codice comprendere la nostra app per comprendere meglio back4app, esploriamo esempi di codice delle operazioni parse in un'applicazione flutter con i principali tipi di dati supportati questa guida non spiegherà alcun codice dell'app flutter poiché l'attenzione principale è sull'uso di parse con flutter prerequisiti per completare questo tutorial, avrai bisogno di android studio https //developer android com/studio o vs code installato (con plugin dart e flutter) un'app creata su back4app nota segui il tutorial nuova app parse per imparare a creare un'app parse su back4app un'app flutter collegata a back4app nota segui il installa il parse sdk nel progetto flutter per creare un progetto flutter collegato a back4app un dispositivo (o dispositivo virtuale) che esegue android o ios 1 lavorare con gli oggetti parse ogni parseobject ha un nome di classe (ad es , gamepoint) utilizzato per distinguere i diversi tipi di dati ecco come puoi creare e salvare un nuovo oggetto parse con tipi di dati string , int , & boolean final gamepoint = parseobject('gamepoint') set('score', 1337) set('playername', 'sean plott') set('cheatmode', false); await gamepoint save(); per interrogare il nuovo oggetto parse e recuperare i tipi di dati final querybuilder\<parseobject> querygamepoints = querybuilder\<parseobject>(parseobject('gamepoint')); final parseresponse response = await querygamepoints query(); if (response success && response results != null) { for (var gamepoint in response results!) { final score = gamepoint get\<int>('score'); final playername = gamepoint get\<string>('playername'); final cheatmode = gamepoint get\<bool>('cheatmode'); } 2 contatori puoi incrementare o decrementare un campo intero in un parseobject utilizzando il set() metodo tuttavia, questo non è efficace e può portare a problemi se più client stanno cercando di aggiornare lo stesso contatore parse fornisce due metodi che incrementano e decrementano automaticamente qualsiasi campo numerico per memorizzare dati di tipo contatore setincrement() setdecrement() un aggiornamento per incrementare un contatore int valore sarà scritto come final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setincrement('intfield', 1); await gamepoint save(); per decrementare final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setdecrement('intfield', 1); await gamepoint save(); utilizzando setincrement() e setdecrement() con la chiamata save() ti consente di aggiornare un valore come parte di un'operazione di salvataggio più ampia in cui potresti modificare più campi questo è meglio per evitare richieste di rete extra 3 liste parse fornisce metodi per lavorare con i dati delle liste, inclusi setadd , setaddunique , setremove , e le loro rispettive versioni all lista \["a","b","c"] 3 1 setadd final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setadd('liststringfield', 'd'); await gamepoint save(); risultato \["a","b","c","d"] 3 2 setaddall final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setaddall('liststringfield', \['e','f']); await gamepoint save(); risultato \["a","b","c","d","e","f"] setaddall non aggiunge elementi duplicati se la lista li contiene già 3 3 setaddunique final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setaddunique('liststringfield', \['a', 'e', 'g']); await gamepoint save(); risultato \["a","b","c","d","e","f","g"] 3 4 setremove final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setremove('liststringfield', 'd'); await gamepoint save(); risultato \["a","b","c","e","f","g"] 4 rimuovi campo da parseobject puoi eliminare un singolo campo da un oggetto utilizzando l'operazione unset final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' unset("liststringfield"); 5 file parsefile ti consente di memorizzare e recuperare file dell'applicazione nel cloud di seguito è riportato un esempio di base per caricare un file immagine locale su back4app // create parsefile object final parsefile = parsefile(file(image path)); final response = await parsefile save(); if (response success) { print('file uploaded successfully ${parsefile url}'); // save this file in an object final gamepoint = parseobject('gamepoint') set('title', 'post with an image') set('imagefile', parsefile); // saving the file as a field final postresponse = await gamepoint save(); } questo frammento di codice mostra come recuperare il file immagine final query = querybuilder\<parseobject>(parseobject('gamepoint')); final response = await query query(); if (response success && response results != null) { for (var gamepoint in response results!) { parsefilebase? varfile = gamepoint get\<parsefilebase>('file'); if (varfile != null) { final fileurl = varfile url; print('game title image url $fileurl'); } else { print('no file found for this object '); } } } a partire da parse server 5 2 3 ci sono modifiche che potrebbero causare errori durante un tentativo di caricare file segui questa guida https //www back4app com/docs/platform/parse server version#o cil per risolvere eventuali problemi di caricamento che potresti riscontrare una guida successiva discuterà ulteriormente e mostrerà modelli su come salvare e visualizzare file con parse https //www back4app com/docs/flutter/parse sdk/flutter save file 6 geopoint parse ti consente di associare coordinate di latitudine e longitudine del mondo reale a un oggetto con il suo tipo di dato geopoint aggiungere un parsegeopoint a un parseobject abiliterà le query a considerare la prossimità di un oggetto a un punto di riferimento esempio // request permission here and get the current location the `position` object // create geopoint object final geopoint = parsegeopoint(latitude position latitude, longitude position longitude); // create an object with the geopoint final gamepoint = parseobject('gamepoint') set('name', 'current location') set('location', geopoint); // save the geopoint in a field final response = await gamepoint save(); puoi trovare un esempio autonomo di salvataggio della posizione geopoint in questo main dart https //github com/templates back4app/flutter datatypes/blob/18c4c372eb49c1cd950eeaac355564134a5e70c4/lib/src/main dart file esempio completo dell'app questo esempio dimostra come crea, elimina e aggiorna un gamepoint oggetto parse gestisci vari tipi di dati, inclusi stringhe, doppi, booleani, file, geopoint, elenchi e date su ios, dovrai concedere al tuo simulatore le necessarie autorizzazioni di accesso ios fornisce una guida per sviluppatori sulle risorse protette le applicazioni di esempio in questa guida richiederanno le chiavi di autorizzazione per posizione https //developer apple com/documentation/bundleresources/information property list/nslocationwheninuseusagedescription e foto https //developer apple com/documentation/bundleresources/information property list/nsphotolibraryaddusagedescription trovate in quella guida per funzionare aggiungi le chiavi al file info plist situato in /ios/runner/info plist puoi saltare il passaggio sopra se stai eseguendo la tua app flutter sul web import 'dart\ async'; import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk flutter dart'; import 'package\ image picker/image picker dart'; import 'package\ flutter/foundation dart'; import 'dart\ io'; void main() async { widgetsflutterbinding ensureinitialized(); const keyparseapplicationid = 'your application id'; const keyparseclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; await parse() initialize( keyparseapplicationid, keyparseserverurl, clientkey keyparseclientkey, autosendsessionid true, debug true, ); runapp(const myapp()); } class myapp extends statelesswidget { const myapp({super key}); @override widget build(buildcontext context) { return materialapp( title 'datatypes', theme themedata( primaryswatch colors blue, ), home const myhomepage(), ); } } class myhomepage extends statefulwidget { const myhomepage({super key}); @override myhomepagestate createstate() => myhomepagestate(); } class myhomepagestate extends state\<myhomepage> { final texteditingcontroller stringcontroller = texteditingcontroller(); final texteditingcontroller doublecontroller = texteditingcontroller(); final texteditingcontroller liststringcontroller = texteditingcontroller(); final texteditingcontroller listintcontroller = texteditingcontroller(); final texteditingcontroller pointercontroller = texteditingcontroller(); final texteditingcontroller objectidcontroller = texteditingcontroller(); final texteditingcontroller uniquevaluecontroller = texteditingcontroller(); final texteditingcontroller removevaluecontroller = texteditingcontroller(); bool boolvalue = false; datetime selecteddate = datetime now(); final string responsemessage = ''; xfile? pickedfile; bool isloading = false; @override widget build(buildcontext context) { return scaffold( appbar appbar( title const text('datatypes'), ), body padding( padding const edgeinsets all(16 0), child singlechildscrollview( child column( crossaxisalignment crossaxisalignment start, children \<widget>\[ buildtextfield('string field', stringcontroller), const sizedbox(height 20), buildtextfield('double field', doublecontroller, isnumeric true), const sizedbox(height 20), buildswitch('bool field', boolvalue, (value) { setstate(() { boolvalue = value; }); }), const sizedbox(height 20), textbutton( onpressed () => selectdate(context), child text( 'select date ${ selecteddate tolocal()}' split(' ')\[0]), ), const sizedbox(height 20), buildtextfield( 'list string field (comma separated)', liststringcontroller), const sizedbox(height 20), buildtextfield( 'list int field (comma separated)', listintcontroller), const sizedbox(height 20), buildtextfield('pointer field (object id)', pointercontroller), const sizedbox(height 20), buildimagepicker(), const sizedbox(height 20), elevatedbutton( onpressed savedata, child const text('save'), ), const sizedbox(height 20), elevatedbutton( onpressed () async { await deletedata( objectidcontroller text); // await dummyfunction(); }, child const text('delete'), ), const sizedbox(height 20), buildtextfield( 'object id to delete or update', objectidcontroller), elevatedbutton( onpressed () async { await updatedata( objectidcontroller text); }, child const text('update'), ), const sizedbox(height 20), buildincrementdecrementbuttons(), const sizedbox(height 20), buildlistoperations(), const sizedbox(height 20), text( responsemessage), ], ), ), ), ); } widget buildtextfield(string label, texteditingcontroller controller, {bool isnumeric = false}) { return textfield( controller controller, keyboardtype isnumeric ? textinputtype number textinputtype text, decoration inputdecoration( border const outlineinputborder(), labeltext label, ), ); } widget buildswitch(string label, bool value, function(bool) onchanged) { return switchlisttile( title text(label), value value, onchanged onchanged, ); } widget buildimagepicker() { return gesturedetector( child pickedfile != null ? container( width 250, height 250, decoration boxdecoration(border border all(color colors blue)), child kisweb ? image network(pickedfile! path) image file(file(pickedfile! path)), ) container( width 250, height 250, decoration boxdecoration(border border all(color colors blue)), child const center( child text('click here to pick image from gamepoint')), ), ontap () async { final picker = imagepicker(); xfile? image = (await picker pickimage(source imagesource gallery)); if (image != null) { setstate(() { pickedfile = image; }); } }, ); } widget buildincrementdecrementbuttons() { return row( mainaxisalignment mainaxisalignment spacebetween, children \[ expanded( child elevatedbutton( onpressed () async { await incrementfield( objectidcontroller text); }, child const text('+ double'), ), ), const sizedbox(width 10), // adding some space between buttons expanded( child elevatedbutton( onpressed () async { await decrementfield( objectidcontroller text); }, child const text(' double'), ), ), ], ); } widget buildlistoperations() { return column( children \[ buildtextfield('unique value to add', uniquevaluecontroller), elevatedbutton( onpressed () async { await adduniquetolist( objectidcontroller text, uniquevaluecontroller text); }, child const text('add unique'), ), const sizedbox(height 20), buildtextfield('value to remove', removevaluecontroller), elevatedbutton( onpressed () async { await removefromlist( objectidcontroller text, removevaluecontroller text); }, child const text('remove'), ), ], ); } future\<void> savedata() async { //parse values string stringvalue = stringcontroller text; list\<string> liststringvalue = liststringcontroller text isnotempty ? liststringcontroller text split(',') // split by comma map((e) => e trim()) // remove any surrounding whitespace from each element tolist() \[]; list\<int> listtintvalue = listintcontroller text isnotempty ? listintcontroller text split(',') // split by comma map( (e) => int parse(e trim())) // convert each string to an integer tolist() \[]; double? doublevalue; if ( doublecontroller text isnotempty) { doublevalue = double parse( doublecontroller text); } bool boolvalue = boolvalue; datetime selecteddate = selecteddate; final gamepoint = parseobject('gamepoint') set('bool', boolvalue) set('date', selecteddate); if (stringvalue isnotempty) gamepoint set('string', stringvalue); if (doublevalue != null) gamepoint set('double', doublevalue); if (liststringvalue isnotempty) { gamepoint setaddall('liststring', liststringvalue); } if (listtintvalue isnotempty) gamepoint setaddall('listint', listtintvalue); if ( pointercontroller text isnotempty) { gamepoint set('pointer', parsepointer( pointercontroller text)); } if (pickedfile != null) { setstate(() { isloading = true; }); parsefilebase? parsefile; if (kisweb) { parsefile = parsewebfile(await pickedfile! readasbytes(), name 'file jpg'); } else { parsefile = parsefile(file(pickedfile! path)); } await parsefile save(); gamepoint set('file', parsefile); } var apiresponse = await gamepoint save(); if (apiresponse success && apiresponse results != null) { setstate(() { isloading = false; pickedfile = null; }); scaffoldmessenger of(context) removecurrentsnackbar() showsnackbar(const snackbar( content text( 'file saved successfully on back4app', style textstyle(color colors white), ), duration duration(seconds 3), backgroundcolor colors blue, )); } else { print("this is your request error ${apiresponse error}"); } } future\<void> updatedata(string objectid) async { final gamepoint = parseobject('gamepoint') objectid = objectid; // update fields with new values if ( stringcontroller text isnotempty) { gamepoint set('string', stringcontroller text); } if ( doublecontroller text isnotempty) { gamepoint set('double', double parse( doublecontroller text)); } gamepoint set('bool', boolvalue); gamepoint set('date', selecteddate); if ( liststringcontroller text isnotempty) { list\<string> liststringvalue = liststringcontroller text split(',') map((e) => e trim()) tolist(); gamepoint setaddall('liststring', liststringvalue); } if ( listintcontroller text isnotempty) { list\<int> listintvalue = listintcontroller text split(',') map((e) => int parse(e trim())) tolist(); gamepoint setaddunique('listint', listintvalue); } if ( pointercontroller text isnotempty) { gamepoint set('pointer', parsepointer( pointercontroller text)); } if (pickedfile != null) { parsefilebase? parsefile; if (kisweb) { parsefile = parsewebfile(await pickedfile! readasbytes(), name 'file jpg'); } else { parsefile = parsefile(file(pickedfile! path)); } await parsefile save(); gamepoint set('file', parsefile); } // save the updated object var response = await gamepoint save(); if (response success) { scaffoldmessenger of(context) showsnackbar( const snackbar(content text('data updated successfully!')), ); } else { scaffoldmessenger of(context) showsnackbar( snackbar( content text('error updating data ${response error! message}')), ); } } future\<void> incrementfield(string objectid) async { final gamepoint = parseobject('gamepoint') objectid = objectid setincrement('double', 1); await gamepoint save(); } future\<void> decrementfield(string objectid) async { final gamepoint = parseobject('gamepoint') objectid = objectid setdecrement('double', 1); await gamepoint save(); } future\<void> adduniquetolist(string objectid, string value) async { final gamepoint = parseobject('gamepoint') objectid = objectid setaddunique('liststring', value); await gamepoint save(); } future\<void> removefromlist(string objectid, string value) async { final gamepoint = parseobject('gamepoint') objectid = objectid setremove('liststring', value); await gamepoint save(); } future\<void> selectdate(buildcontext context) async { final datetime? picked = await showdatepicker( context context, initialdate selecteddate, firstdate datetime(2000), lastdate datetime(2101), ); if (picked != null && picked != selecteddate) { setstate(() { selecteddate = picked; }); } } future\<void> deletedata(string objectid) async { // delete data logic final parseobject = parseobject('gamepoint') objectid = objectid unset("liststring"); await parseobject save(); } // convert pointer field to a suitable format parseobject parsepointer(string objectid) { // there should be an existing game class with objects final pointer = parseobject('game') objectid = objectid; return pointer; } } questo codice inizializza il parse sdk in flutter, imposta l'applicazione principale e visualizza una semplice home page con un titolo conclusione in questa guida, hai imparato a conoscere i parseobjects e i vari tipi di dati disponibili per parse hai anche imparato come gestire operazioni come il salvataggio e il recupero dei tipi di dati dal tuo backend di back4app