Парсинг и хранение типов данных на Android c Back4App
23 мин
парсинг типов данных на android введение в этом руководстве вы узнаете о типах данных parse, используя android вы будете читать и сохранять объекты parse на back4app из android приложения хранение данных в parse основано на \<font color="#2166ae">parseobject\</font> каждый \<font color="#2166ae">parseobject\</font> содержит пары ключ значение совместимых с json данных эти данные не имеют схемы, что означает, что нам не нужно заранее указывать, какие ключи существуют в каждом \<font color="#2166ae">parseobject\</font> мы можем устанавливать любые пары ключ значение, которые хотим, и наш бэкенд будет их хранить например, предположим, что мы отслеживаем высокие результаты для игры один \<font color="#2166ae">parseobject\</font> может содержать 1 score 1337 , playername "шон плотт" , cheatmode false ключи должны быть алфавитно цифровыми строками, а значения могут быть \<font color="#2166ae">строка\</font> => \<font color="#2166ae">строка\</font> \<font color="#2166ae">число\</font> (примитивные числовые значения, такие как \<font color="#2166ae">int\</font> , \<font color="#2166ae">double\</font> ) \<font color="#2166ae">булевый\</font> => \<font color="#2166ae">boolean\</font> \<font color="#2166ae">дата и время\</font> => java util date \<font color="#2166ae">ноль\</font> => jsonobject null \<font color="#2166ae">массив\</font> =>jsonarray \<font color="#2166ae">файл\</font> => parse file \<font color="#2166ae">указатель\</font> => другой parseobject \<font color="#2166ae">связь\</font> => parserelation \<font color="#2166ae">геоточка\</font> => parsegeopoint каждый \<font color="#2166ae">parseobject\</font> имеет имя класса, которое мы можем использовать для различения различных типов данных например, мы могли бы назвать объект высокого счета \<font color="#2166ae">gamescore\</font> также есть несколько полей, которые нам не нужно указывать, так как они предоставляются для удобства \<font color="#2166ae">objectid\</font> является уникальным идентификатором для каждого сохраненного объекта \<font color="#2166ae">createdat\</font> и \<font color="#2166ae">updatedat\</font> представляют время, когда каждый объект был создан и последний раз изменен в облаке каждое из этих полей автоматически заполняется back4app в момент, когда мы сохраняем новый \<font color="#2166ae">parseobject\</font> мы рекомендуем вам \<font color="#2166ae">nameyourclasseslikethis\</font> (uppercamelcase) и \<font color="#2166ae">nameyourkeyslikethis \</font> (lowercamelcase), просто чтобы ваш код выглядел красиво этот учебник использует базовое приложение, созданное в android studio 4 1 1 с \<font color="#2166ae">buildtoolsversion=30 0 2\</font> , \<font color="#2166ae">compile sdk version\</font> = \<font color="#2166ae">30 0 2\</font> и \<font color="#2166ae">targetsdkversion 30\</font> в любое время вы можете получить доступ к полному проекту через наши репозитории на github репозиторий примера на kotlin https //github com/templates back4app/android crud operations kotlin репозиторий примера на java https //github com/templates back4app/android crud operations java цель наша цель создать android приложение, которое может обрабатывать все типы данных, предоставляемые parse server вот предварительный просмотр того, что мы собираемся достичь предварительные требования чтобы завершить этот учебник, нам нужно android studio https //developer android com/studio/index html приложение, созданное на back4app примечание следуйте за учебником по созданию нового parse app https //www back4app com/docs/get started/new parse app чтобы узнать, как создать parse app на back4app android приложение, подключенное к back4app примечание следуйте за учебником по установке parse sdk https //www back4app com/docs/android/parse android sdk чтобы создать проект android studio, подключенный к back4app устройство (или виртуальное устройство https //developer android com/studio/run/managing avds html ) с android 4 1 (jelly bean) или новее понимание нашего приложения вы создадите приложение для лучшего понимания parse \<font color="#2166ae">типы данных\</font> в этом \<font color="#2166ae">android\</font> приложении вы создадите все типы данных в классе с именем \<font color="#2166ae">datatypes\</font> и присвоите значения переменным этого класса затем мы будем читать и обновлять эти данные примечание типы данных \<font color="#2166ae">указатель\</font> , \<font color="#2166ae">связь\</font> , \<font color="#2166ae">файл\</font> , \<font color="#2166ae">геоточка\</font> будут рассмотрены позже в специальных руководствах давайте начнем! 1 создать шаблон приложения определите следующие переменные в \<font color="#2166ae">mainactivity\</font> и замените код в методе \<font color="#2166ae">oncreate\</font> следующим кодом 1 private progressdialog progressdialog; 2 private view popupinputdialogview; 3 private recyclerview recyclerview; 4 private string objectid; 5 private static final string tag = "mainactivity"; 6 7 @override 8 protected void oncreate(bundle savedinstancestate) { 9 super oncreate(savedinstancestate); 10 setcontentview(r layout activity main); 11 12 progressdialog = new progressdialog(mainactivity this); 13 14 button savedata = findviewbyid(r id savedata); 15 button readdata = findviewbyid(r id readdata); 16 button updatedata = findviewbyid(r id updatedata); 17 18 savedata setonclicklistener(savedataview > { 19 try { 20 savedatatypes(); 21 } catch (jsonexception e) { 22 e printstacktrace(); 23 } 24 }); 25 26 readdata setonclicklistener(readdataview > readobjects()); 27 28 updatedata setonclicklistener(updatedataview > updateobject()); 29 30 }1 private var progressdialog progressdialog? = null 2 private var objectid string? = null 3 private var popupinputdialogview view? = null 4 private var recyclerview recyclerview? = null 5 private val tag = "mainactivity" 6 7 override fun oncreate(savedinstancestate bundle?) { 8 super oncreate(savedinstancestate) 9 setcontentview(r layout activity main) 10 11 progressdialog = progressdialog(this\@mainactivity) 12 val savedata = findviewbyid\<button>(r id savedata) 13 val readdata = findviewbyid\<button>(r id readdata) 14 val updatedata = findviewbyid\<button>(r id updatedata) 15 16 savedata setonclicklistener { 17 try { 18 savedatatypes() 19 } catch (e jsonexception) { 20 e printstacktrace() 21 } 22 } 23 readdata setonclicklistener { readobjects() } 24 updatedata setonclicklistener { updateobject() } 25 } перед следующими шагами нам нужно подключить \<font color="#2166ae">back4app\</font> к нашему приложению вам следует сохранить \<font color="#2166ae">appid\</font> и \<font color="#2166ae">clientkey\</font> из \<font color="#2166ae">back4app\</font> в файл \<font color="#2166ae">string xml\</font> и затем инициализировать \<font color="#2166ae">parse\</font> в нашем файле \<font color="#2166ae">app java\</font> или \<font color="#2166ae">app kt\</font> следуйте за новым учебником по parse app https //www back4app com/docs/android/parse android sdk если вы не знаете, как инициализировать \<font color="#2166ae">parse\</font> в вашем приложении 2 код для сохранения объекта функция create создаст новый объект в базе данных back4app мы определяем функцию \<font color="#2166ae">savedatatypes\</font> которую мы вызываем в функции \<font color="#2166ae">oncreate\</font> и используем следующий код в этой функции мы сохраним все типы данных с помощью этой функции в объект классов datatypes 1 private void savedatatypes() throws jsonexception{ 2 parseobject parseobject = new parseobject("datatypes"); 3 4 parseobject put("stringfield", "string"); 5 parseobject put("doublefield", 1 5); 6 parseobject put("intfield", 2); 7 parseobject put("boolfield", true); 8 parseobject put("datefield", calendar getinstance() gettime()); 9 10 jsonobject myobject = new jsonobject(); 11 myobject put("number", 1); 12 myobject put("string", "42"); 13 14 parseobject put("jsonobject", myobject); 15 16 17 jsonarray myarray = new jsonarray(); 18 myarray put(myobject); 19 myarray put(myobject); 20 myarray put(myobject); 21 22 parseobject put("jsonarray", myarray); 23 24 25 list\<string> list = new arraylist<>(); 26 list add("string1"); 27 list add("string2"); 28 parseobject put("liststringfield", list); 29 30 list\<integer> listint = new arraylist<>(); 31 listint add(1); 32 listint add(2); 33 listint add(3); 34 parseobject put("listintfield", listint); 35 36 list\<boolean> listbool = new arraylist<>(); 37 listbool add(true); 38 listbool add(false); 39 parseobject put("listboolfield", listbool); 40 41 progressdialog show(); 42 parseobject saveinbackground(e > { 43 progressdialog dismiss(); 44 if (e == null) { 45 toast maketext(this, "object created successfully ", toast length short) show(); 46 objectid = parseobject getobjectid(); 47 } else { 48 objectid = null; 49 toast maketext(this, e getmessage(), toast length long) show(); 50 } 51 }); 52 }1 private fun savedatatypes() { 2 val parseobject = parseobject("datatypes") 3 4 parseobject put("stringfield", "string") 5 parseobject put("doublefield", 1 5) 6 parseobject put("intfield", 2) 7 parseobject put("boolfield", true) 8 parseobject put("datefield", calendar getinstance() time) 9 10 11 val myobject = jsonobject() 12 myobject put("number", 1) 13 myobject put("string", "42") 14 15 parseobject put("jsonobject", myobject) 16 17 val myarray = jsonarray() 18 myarray put(myobject) 19 myarray put(myobject) 20 myarray put(myobject) 21 22 parseobject put("jsonarray", myarray) 23 24 val list mutablelist\<string> = arraylist() 25 list add("string1") 26 list add("string2") 27 parseobject put("liststringfield", list) 28 29 val listint mutablelist\<int> = arraylist() 30 listint add(1) 31 listint add(2) 32 listint add(3) 33 parseobject put("listintfield", listint) 34 35 val listbool mutablelist\<boolean> = arraylist() 36 listbool add(true) 37 listbool add(false) 38 parseobject put("listboolfield", listbool) 39 40 progressdialog? show() 41 parseobject saveinbackground { 42 progressdialog? dismiss() 43 if (it == null) { 44 toast maketext(this, "object created successfully ", toast length short) show() 45 objectid = parseobject objectid 46 } else { 47 objectid = null 48 toast maketext(this, it message, toast length long) show() 49 } 50 } 51 } 3 код для чтения объекта мы передадим переменную \<font color="#2166ae">objectid\</font> , которую мы назначили в функции \<font color="#2166ae">savedatatypes\</font> в качестве параметра запроса и прочитаем данные, которые мы сохранили в функции \<font color="#2166ae">savedatatypes\</font> с помощью функции \<font color="#2166ae">readobjects\</font> 1 private void readobjects() { 2 if (objectid == null) { 3 toast maketext(this, "no object click on the 'save data' button before ", toast length short) show(); 4 return; 5 } 6 7 parsequery\<parseobject> query = new parsequery<>("datatypes"); 8 9 progressdialog show(); 10 query getinbackground(objectid, (object, e) > { 11 progressdialog dismiss(); 12 if (e == null) { 13 list\<data> list = new arraylist<>(); 14 list add(new data("int list field",object get("listintfield") tostring())); 15 list add(new data("string field",object get("stringfield") tostring())); 16 list add(new data("double field",object get("doublefield") tostring())); 17 list add(new data("int field",object get("intfield") tostring())); 18 list add(new data("string list field",object get("liststringfield") tostring())); 19 list add(new data("date field",object get("datefield") tostring())); 20 list add(new data("bool field",object get("boolfield") tostring())); 21 list add(new data("list bool field",object get("listboolfield") tostring())); 22 list add(new data("json object field",object get("jsonobject") tostring())); 23 list add(new data("json array field",object get("jsonarray") tostring())); 24 25 showdatatypes(list); 26 27 } else { 28 toast maketext(this, e getmessage(), toast length short) show(); 29 } 30 }); 31 }1 private fun readobjects() { 2 if (objectid == null) { 3 toast maketext( 4 this, 5 "no object click on the 'save data' button before ", 6 toast length short 7 ) show() 8 return 9 } 10 11 val query = parsequery\<parseobject>("datatypes") 12 13 14 progressdialog? show() 15 query getinbackground( 16 objectid 17 ) { obj, e > 18 progressdialog? dismiss() 19 if (e == null) { 20 21 val list mutablelist\<data> = arraylist() 22 list add(data("int list field", obj get("listintfield") tostring())) 23 list add(data("string field",obj get("stringfield") tostring())) 24 list add(data("double field", obj get("doublefield") tostring())) 25 list add(data("int field", obj get("intfield") tostring())) 26 list add(data("string list field", obj get("liststringfield") tostring())) 27 list add(data("date field",obj get("datefield") tostring())) 28 list add(data("bool field", obj get("boolfield") tostring())) 29 list add(data("list bool field", obj get("listboolfield") tostring())) 30 list add(data("json object field", obj get("jsonobject") tostring())) 31 list add(data("json array field", obj get("jsonarray") tostring())) 32 showdatatypes(list) 33 } else { 34 toast maketext(this, e message, toast length short) show() 35 } 36 37 } 38 } в этом разделе мы создали класс модели под названием \<font color="#2166ae">data\</font> мы используем данные, которые получаем в функции \<font color="#2166ae">readobjects\</font> , чтобы создавать объекты из этого класса модели мы передаем эти объекты как элементы в список, который мы создали в \<font color="#2166ae">data\</font> типа затем мы передаем этот список в качестве параметра функции \<font color="#2166ae">showdatatypes\</font> и выводим его в \<font color="#2166ae">alertdialog\</font> это \<font color="#2166ae">данные\</font> модель 1 public class data { 2 private string type; 3 private string value; 4 5 public data(string type, string value) { 6 this type = type; 7 this value = value; 8 } 9 10 public string gettype() { 11 return type; 12 } 13 14 public data settype(string type) { 15 this type = type; 16 return this; 17 } 18 19 public string getvalue() { 20 return value; 21 } 22 23 public data setvalue(string value) { 24 this value = value; 25 return this; 26 } 27 }1 class data(val type\ string?=null,val value\ string?=null) { 2 3 } это \<font color="#2166ae">showdatatypes\</font> функция 1 private void showdatatypes(list\<data> list){ 2 alertdialog builder alertdialogbuilder = new alertdialog builder(mainactivity this); 3 alertdialogbuilder settitle("data types"); 4 alertdialogbuilder setcancelable(true); 5 initpopupviewcontrols(list); 6 //we are setting our custom popup view by alertdialog builder 7 alertdialogbuilder setview(popupinputdialogview); 8 final alertdialog alertdialog = alertdialogbuilder create(); 9 alertdialog show(); 10 } 11 12 private void initpopupviewcontrols(list\<data> list) { 13 layoutinflater layoutinflater = layoutinflater from(mainactivity this); 14 popupinputdialogview = layoutinflater inflate(r layout custom alert dialog, null); 15 recyclerview = popupinputdialogview\ findviewbyid(r id recyclerview); 16 itemadapter adapter = new itemadapter(list,this); 17 recyclerview\ setlayoutmanager(new linearlayoutmanager(this,linearlayoutmanager vertical,false)); 18 recyclerview\ setadapter(adapter); 19 }1 private fun showdatatypes(list list\<data>) { 2 val alertdialogbuilder = alertdialog builder(this\@mainactivity) 3 alertdialogbuilder settitle("data types") 4 alertdialogbuilder setcancelable(true) 5 initpopupviewcontrols(list) 6 //we are setting our custom popup view by alertdialog builder 7 alertdialogbuilder setview(popupinputdialogview) 8 val alertdialog = alertdialogbuilder create() 9 alertdialog show() 10 } 11 12 @suppresslint("inflateparams") 13 private fun initpopupviewcontrols(list list\<data>) { 14 val layoutinflater = layoutinflater from(this\@mainactivity) 15 popupinputdialogview = layoutinflater inflate(r layout custom alert dialog, null) 16 recyclerview = popupinputdialogview? findviewbyid(r id recyclerview) 17 val adapter = itemadapter(this\@mainactivity, list) 18 recyclerview? layoutmanager = linearlayoutmanager( 19 this, 20 linearlayoutmanager vertical, 21 false 22 ) 23 recyclerview? adapter = adapter 24 } 4 код для обновления объекта функция \<font color="#2166ae">updateobject\</font> отвечает за обновление данных в объекте, созданном с помощью функции \<font color="#2166ae">savedatatypes\</font> мы снова используем \<font color="#2166ae">objectid\</font> для обновления объекта 1 public void updateobject() { 2 if (objectid == null) { 3 toast maketext(this, "no object click on the 'save data' button before ", toast length short) show(); 4 return; 5 } 6 7 parseobject parseobject = new parseobject("datatypes"); 8 parseobject setobjectid(objectid); 9 parseobject put("intfield", 5); 10 parseobject put("stringfield", "new string"); 11 12 progressdialog show(); 13 14 parseobject saveinbackground(e > { 15 progressdialog dismiss(); 16 if (e == null) { 17 toast maketext(this, "object updated successfully ", toast length short) show(); 18 } else { 19 toast maketext(this, e getmessage(), toast length short) show(); 20 } 21 }); 22 }1 private fun updateobject() { 2 if (objectid == null) { 3 toast maketext( 4 this, 5 "no object click on the 'save data' button before ", 6 toast length short 7 ) show() 8 return 9 } 10 11 val parseobject = parseobject("datatypes") 12 parseobject objectid = objectid 13 parseobject put("intfield", 5) 14 parseobject put("stringfield", "new string") 15 16 progressdialog? show() 17 18 parseobject saveinbackground { 19 progressdialog? dismiss() 20 if (it == null) { 21 toast maketext(this, "object updated successfully ", toast length short) show() 22 } else { 23 toast maketext(this, it message, toast length short) show() 24 } 25 } 26 } 5 использование счетчиков приведённый выше пример содержит общий случай использования поле \<font color="#2166ae">intfield\</font> может быть счетчиком, который нам нужно будет обновлять постоянно приведённое выше решение работает, но оно громоздкое и может привести к проблемам, если у нас есть несколько клиентов, пытающихся обновить один и тот же счетчик parse предоставляет методы, которые атомарно увеличивают любое числовое поле, чтобы помочь с хранением данных типа счетчика таким образом, то же самое обновление можно переписать как 1 parseobject parseobject = new parseobject("datatypes"); 2 parseobject setobjectid(objectid); 3 parseobject increment("intfield",1);1 val parseobject = parseobject("datatypes") 2 parseobject objectid = objectid 3 parseobject increment("intfield",1) 6 использование списков parse также предоставляет методы для помощи в хранении данных списков существует три операции, которые можно использовать для атомарного изменения поля списка \<font color="#2166ae">setadd\</font> и \<font color="#2166ae">setaddall\</font> добавляет заданные объекты в конец поля массива \<font color="#2166ae">setaddunique\</font> и \<font color="#2166ae">setaddallunique\</font> добавляет только заданные объекты, которые еще не содержатся в поле массива, в это поле позиция вставки не гарантируется \<font color="#2166ae">remove\</font> и \<font color="#2166ae">removeall\</font> удаляет все экземпляры заданных объектов из поля массива 6 1 примеры с add и addall \<font color="#2166ae">liststringfield\</font> имеет значение \["a","b","c","d","e","f","g","g"] запуск кода ниже 1 parseobject parseobject = new parseobject("datatypes"); 2 parseobject setobjectid(objectid); 3 parseobject add("liststringfield","e"); 4 parseobject addall("liststringfield", arrays aslist("e", "f", "g", "g")); 5 parseobject save();1 val parseobject = parseobject("datatypes") 2 parseobject objectid = objectid 3 parseobject add("liststringfield", "e") 4 parseobject addall("liststringfield", arrays aslist("e", "f", "g", "g")) 5 parseobject save() после этой команды результат поля stringlist будет \["a","b","c","d","e","e","f","g","g"] 6 2 примеры с addunique и addallunique \<font color="#2166ae">liststringfield\</font> имеет значение \["a","b","c","d","e"] запуск кода ниже 1 parseobject parseobject = new parseobject("datatypes"); 2 parseobject setobjectid(objectid); 3 parseobject addunique("liststringfield","e"); 4 parseobject addallunique("liststringfield",arrays aslist("c", "d", "e", "f")); 5 parseobject save();1 val parseobject = parseobject("datatypes") 2 parseobject objectid = objectid 3 parseobject addunique("liststringfield", "e") 4 parseobject addallunique("liststringfield", arrays aslist("c", "d", "e", "f")) 5 parseobject save() после этой команды результат поля \<font color="#2166ae">stringlist\</font> будет \["a","b","c","d","e","f"] значения не повторялись 6 3 примеры с removeall \<font color="#2166ae">liststringfield\</font> имеет значение \["a","b","c","d","e","f"] запуск кода ниже 1 parseobject parseobject = new parseobject("datatypes"); 2 parseobject setobjectid(objectid); 3 parseobject removeall("liststringfield",arrays aslist("c", "d", "e", "f")); 4 parseobject save();1 val parseobject = parseobject("datatypes") 2 parseobject objectid = objectid 3 parseobject removeall("liststringfield", arrays aslist("c", "d", "e", "f")) 4 parseobject save() после этой команды результат поля \<font color="#2166ae">stringlist\</font> будет \["a","b"] примечание что в настоящее время невозможно атомарно добавлять и удалять элементы из массива в одном сохранении нам придется вызывать сохранение для каждой отдельной операции с массивом 7 удалить одно поле из parseobject вы можете удалить одно поле из объекта, используя \<font color="#2166ae">remove\</font> операцию 1 parseobject parseobject = new parseobject("datatypes"); 2 parseobject remove("stringfield"); 3 parseobject save();1 val parseobject = parseobject("datatypes") 2 parseobject remove("stringfield") 3 parseobject save() готово! на данный момент мы узнали о \<font color="#2166ae">типах данных parse\</font> на \<font color="#2166ae">android\</font>