Flutter
...
Data Objects
จัดการ Parse SDK ใน Flutter สำหรับนักพัฒนาแอปพลิเคชัน
17 นาที
คู่มือนี้แนะนำประเภทข้อมูล parse ใน flutter โดยใช้ตัวอย่างจาก main dart ไฟล์ การจัดเก็บข้อมูล parse หมุนรอบ parseobject ซึ่งประกอบด้วยคู่คีย์ ค่า ของข้อมูลที่เข้ากันได้กับ json ทำให้ไม่มีสคีมา นี่หมายความว่าคุณสามารถจัดเก็บข้อมูลใด ๆ โดยไม่ต้องกำหนดสคีมาไว้ล่วงหน้า คุณสามารถตั้งค่าคู่คีย์ ค่า ใด ๆ ที่คุณต้องการ และแบ็กเอนด์ของเราจะจัดเก็บพวกมัน ตัวอย่างเช่น สมมติว่าคุณกำลังติดตามคะแนนสูงสุดสำหรับเกม อ็อบเจ็กต์ parse เดียวอาจประกอบด้วย คะแนน 1337, ชื่อผู้เล่น "sean plott", โหมดโกง false เราขอแนะนำให้คุณ nameyourclasseslikethis และ nameyourkeyslikethis เพื่อเพิ่มความสามารถในการอ่านและการบำรุงรักษาโค้ด การทำความเข้าใจแอปของเรา เพื่อให้เข้าใจ back4app ได้ดีขึ้น มาสำรวจตัวอย่างโค้ดของการดำเนินการ parse ในแอปพลิเคชัน flutter พร้อมกับประเภทข้อมูลที่รองรับหลัก คู่มือนี้จะไม่อธิบายโค้ดแอป flutter ใด ๆ เนื่องจากจุดสนใจหลักคือการใช้ parse กับ flutter ข้อกำหนดเบื้องต้น เพื่อให้เสร็จสิ้นการสอนนี้ คุณจะต้องมี https //developer android com/studio หรือ https //code visualstudio com/ (พร้อมกับ https //docs flutter dev/get started/editor dart และ flutter) แอป https //www back4app com/docs/get started/new parse app บน back4app หมายเหตุ ติดตาม https //www back4app com/docs/get started/new parse app เพื่อเรียนรู้วิธีการสร้าง parse app บน back4app แอป flutter ที่เชื่อมต่อกับ back4app หมายเหตุ ติดตาม https //www back4app com/docs/flutter/parse sdk/parse flutter sdk เพื่อสร้างโปรเจกต์ flutter ที่เชื่อมต่อกับ back4app อุปกรณ์ (หรืออุปกรณ์เสมือน) ที่รัน android หรือ ios 1 การทำงานกับ parse objects แต่ละ parseobject มีชื่อคลาส (เช่น gamepoint) ที่ใช้เพื่อแยกแยะประเภทข้อมูลที่แตกต่างกัน นี่คือวิธีที่คุณสามารถสร้างและบันทึก parse object ใหม่ด้วยประเภทข้อมูล string , int , & boolean final gamepoint = parseobject('gamepoint') set('score', 1337) set('playername', 'sean plott') set('cheatmode', false); await gamepoint save(); เพื่อสอบถามวัตถุ parse ใหม่และดึงประเภทข้อมูล 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 เคาน์เตอร์ คุณสามารถเพิ่มหรือลดฟิลด์จำนวนเต็มใน parseobject โดยใช้ set() วิธีการ อย่างไรก็ตาม นี่ไม่ใช่วิธีที่มีประสิทธิภาพและอาจนำไปสู่ปัญหาได้หากมีลูกค้าหลายรายพยายามอัปเดตเคาน์เตอร์เดียวกัน parse มีวิธีการสองวิธีที่เพิ่มและลดค่าฟิลด์ตัวเลขใด ๆ โดยอัตโนมัติเพื่อจัดเก็บข้อมูลประเภทเคาน์เตอร์ setincrement() setdecrement() การอัปเดตเพื่อเพิ่มค่าของเคาน์เตอร์ int จะถูกเขียนเป็น final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setincrement('intfield', 1); await gamepoint save(); เพื่อลดค่า final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setdecrement('intfield', 1); await gamepoint save(); การใช้ setincrement() และ setdecrement() พร้อมกับการเรียก save() ช่วยให้คุณสามารถอัปเดตค่าเป็นส่วนหนึ่งของการดำเนินการบันทึกที่ใหญ่ขึ้นซึ่งคุณอาจกำลังแก้ไขหลายฟิลด์ นี่เป็นวิธีที่ดีกว่าเพื่อหลีกเลี่ยงการร้องขอเครือข่ายเพิ่มเติม 3 รายการ parse มีวิธีการทำงานกับข้อมูลรายการ รวมถึง setadd , setaddunique , setremove , และเวอร์ชัน all ที่เกี่ยวข้อง รายการ \["a","b","c"] 3 1 setadd final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setadd('liststringfield', 'd'); await gamepoint save(); ผลลัพธ์ \["a","b","c","d"] 3 2 setaddall final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setaddall('liststringfield', \['e','f']); await gamepoint save(); ผลลัพธ์ \["a","b","c","d","e","f"] setaddall จะไม่เพิ่มองค์ประกอบที่ซ้ำกันหากรายการมีอยู่แล้ว 3 3 setaddunique final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setaddunique('liststringfield', \['a', 'e', 'g']); await gamepoint save(); ผลลัพธ์ \["a","b","c","d","e","f","g"] 3 4 setremove final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' setremove('liststringfield', 'd'); await gamepoint save(); ผลลัพธ์ \["a","b","c","e","f","g"] 4 ลบฟิลด์จาก parseobject คุณสามารถลบฟิลด์เดียวจากอ็อบเจ็กต์โดยใช้การดำเนินการ unset final gamepoint = parseobject('gamepoint') objectid = 'yourobjectid' unset("liststringfield"); 5 ไฟล์ parsefile ช่วยให้คุณสามารถจัดเก็บและเรียกคืนไฟล์แอปพลิเคชันใน cloud ได้ ด้านล่างเป็นตัวอย่างพื้นฐานของการอัปโหลดไฟล์ภาพท้องถิ่นไปยัง 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(); } โค้ดนี้แสดงวิธีการเรียกคืนไฟล์ภาพ 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 '); } } } เริ่มต้นจาก parse server 5 2 3 มีการเปลี่ยนแปลงที่อาจทำให้เกิดข้อผิดพลาดในระหว่างการพยายามอัปโหลดไฟล์ ติดตาม https //www back4app com/docs/platform/parse server version#o cil เพื่อแก้ไขปัญหาการอัปโหลดที่คุณอาจพบ คู่มือภายหลังจะพูดคุยและแสดงเทมเพลตเกี่ยวกับวิธีการ https //www back4app com/docs/flutter/parse sdk/flutter save file 6 geopoint parse อนุญาตให้คุณเชื่อมโยงพิกัดละติจูดและลองจิจูดในโลกจริงกับวัตถุด้วยประเภทข้อมูล geopoint ของมัน การเพิ่ม parsegeopoint ลงใน parseobject จะทำให้การค้นหาพิจารณาความใกล้ชิดของวัตถุต่อจุดอ้างอิง ตัวอย่าง // 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(); คุณสามารถค้นหาตัวอย่างที่แยกออกมาเกี่ยวกับการบันทึกตำแหน่ง geopoint ในไฟล์นี้ https //github com/templates back4app/flutter datatypes/blob/18c4c372eb49c1cd950eeaac355564134a5e70c4/lib/src/main dart ตัวอย่างแอปเต็ม ตัวอย่างนี้แสดงให้เห็นว่าวิธีการ สร้าง ลบ และอัปเดต gamepoint อ็อบเจ็กต์ parse จัดการกับประเภทข้อมูลต่างๆ รวมถึงสตริง, ดับเบิล, บูลีน, ไฟล์, จุดภูมิศาสตร์, รายการ และวันที่ บน ios คุณจะต้องให้สิทธิ์การเข้าถึงที่จำเป็นกับซิมูเลเตอร์ของคุณ ios มีคู่มือสำหรับนักพัฒนาที่เกี่ยวกับทรัพยากรที่ได้รับการป้องกัน ตัวอย่างแอปพลิเคชันในคู่มือนี้จะต้องการ https //developer apple com/documentation/bundleresources/information property list/nslocationwheninuseusagedescription และ https //developer apple com/documentation/bundleresources/information property list/nsphotolibraryaddusagedescription คีย์สิทธิ์ที่พบในคู่มือนั้นเพื่อทำงาน เพิ่มคีย์ไปยัง info plist ไฟล์ ซึ่งตั้งอยู่ที่ /ios/runner/info plist คุณสามารถข้ามขั้นตอนข้างต้นได้หากคุณกำลังเรียกใช้แอป flutter ของคุณบนเว็บ 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; } } โค้ดนี้ทำการเริ่มต้น parse sdk ใน flutter ตั้งค่าแอปพลิเคชันหลัก และแสดงหน้าแรกที่เรียบง่ายพร้อมกับชื่อเรื่อง บทสรุป ในคู่มือนี้ คุณได้เรียนรู้เกี่ยวกับ parseobjects และประเภทข้อมูลต่างๆ ที่มีให้กับ parse คุณยังได้เรียนรู้วิธีจัดการกับการดำเนินการต่างๆ เช่น การบันทึกและการดึงข้อมูลประเภทต่างๆ ไปยังและจาก backend ของ back4app ของคุณ