Implementar Relaciones de Objetos en Parse para Android
19 min
relaciones en android introducción usando parse, puedes almacenar objetos de datos estableciendo relaciones entre ellos para modelar este comportamiento, cualquier \<font color="#2166ae">parseobject\</font> puede ser utilizado como un valor en otros \<font color="#2166ae">parseobject\</font> internamente, el marco de parse almacenará el objeto referido en un solo lugar, para mantener la consistencia eso puede darte un poder extra al construir y ejecutar consultas complejas hay tres tipos principales de relaciones \<font color="#2166ae">uno a uno\</font> , estableciendo relaciones directas entre dos objetos y solo ellos; \<font color="#2166ae">uno a muchos\</font> , donde un objeto puede estar relacionado con muchos otros objetos; \<font color="#2166ae">muchos a muchos\</font> , que puede crear muchas relaciones complejas entre muchos objetos hay dos formas de crear una \<font color="#2166ae">relación uno a muchos\</font> en parse la primera es usar los \<font color="#2166ae">punteros\</font> en \<font color="#2166ae">clase hija,\</font> que es el más rápido en tiempo de creación y consulta la segunda es usar \<font color="#2166ae">arreglos\</font> de \<font color="#2166ae">punteros\</font> en clase padre, lo que puede llevar a tiempos de consulta lentos dependiendo de su tamaño debido a este problema de rendimiento, solo usaremos ejemplos de punteros hay tres formas de crear una \<font color="#2166ae">relación muchos a muchos\</font> en parse la primera es usar las \<font color="#2166ae">relaciones\</font> , que es la más rápida en tiempo de creación y consulta usaremos esto en esta guía la segunda es usar \<font color="#2166ae">arreglos\</font> de \<font color="#2166ae">punteros\</font> que pueden llevar a tiempos de consulta lentos dependiendo de su tamaño la tercera es usar \<font color="#2166ae">jointable\</font> donde la idea proviene de bases de datos clásicas cuando hay una relación muchos a muchos, combinamos cada \<font color="#2166ae">objectid\</font> o \<font color="#2166ae">puntero\</font> de ambos lados juntos para construir una nueva tabla separada en la que se rastrea la relación este tutorial utiliza una aplicación básica creada en android studio 4 1 1 con \<font color="#2166ae">buildtoolsversion=30 0 2\</font> , \<font color="#2166ae">compile sdk version = 30 0 2\</font> y \<font color="#2166ae">targetsdkversion 30\</font> en cualquier momento, puedes acceder al proyecto completo de android construido con este tutorial en nuestros repositorios de github repositorio de ejemplo en kotlin https //github com/templates back4app/android parse sdk kotlin repositorio de ejemplo en java https //github com/templates back4app/android parse sdk java objetivo nuestro objetivo es entender las relaciones de parse creando una aplicación práctica de libros aquí hay una vista previa de lo que vamos a lograr requisitos previos para completar este tutorial, necesitamos android studio https //developer android com/studio/index html una aplicación creada en back4app nota sigue el tutorial de nueva aplicación parse https //www back4app com/docs/get started/new parse app para aprender cómo crear una aplicación parse en back4app una aplicación de android conectada a back4app nota sigue el tutorial de instalación del sdk de parse https //www back4app com/docs/android/parse android sdk para crear un proyecto de android studio conectado a back4app un dispositivo (o dispositivo virtual https //developer android com/studio/run/managing avds html ) que ejecute android 4 1 (jelly bean) o más reciente entendiendo la aplicación de libros la clase de objeto principal que estarás utilizando es la \<font color="#2166ae">libro\</font> clase, que almacena cada entrada de libro en el registro además, estas son las otras tres clases de objeto \<font color="#2166ae">editorial\</font> nombre de la editorial del libro, \<font color="#2166ae">uno a muchos\</font> relación con \<font color="#2166ae">libro\</font> \<font color="#2166ae">género\</font> género del libro, \<font color="#2166ae">uno a muchos\</font> relación con \<font color="#2166ae">libro\</font> ten en cuenta que para este ejemplo consideraremos que un libro solo puede tener un género; \<font color="#2166ae">autor\</font> autor del libro, \<font color="#2166ae">muchos a muchos\</font> relación con \<font color="#2166ae">libro\</font> , ya que un libro puede tener más de un autor y un autor puede tener más de un libro también; una representación visual de este modelo de datos ¡empecemos! antes de los siguientes pasos, necesitamos conectar \<font color="#2166ae">back4app\</font> a nuestra aplicación debes guardar el \<font color="#2166ae">appid\</font> y \<font color="#2166ae">clientkey\</font> de \<font color="#2166ae">back4app\</font> a \<font color="#2166ae">string xml\</font> y luego inicializa \<font color="#2166ae">parse\</font> en nuestro \<font color="#2166ae">app java\</font> o \<font color="#2166ae">app kt\</font> archivo sigue el nuevo tutorial de parse app https //www back4app com/docs/android/parse android sdk si no sabes cómo inicializar \<font color="#2166ae">parse\</font> en tu aplicación o puedes descargar los proyectos que compartimos en los enlaces de github arriba y editar solo las partes de \<font color="#2166ae">appid\</font> y \<font color="#2166ae">clientkey\</font> según te convenga 1 guardar y listar objetos relacionados de libros en este paso veremos cómo guardar y listar los \<font color="#2166ae">géneros\</font> , \<font color="#2166ae">editoriales\</font> y \<font color="#2166ae">autores\</font> clases relacionadas con la \<font color="#2166ae">clase de libro\</font> 1 1 guardar y listar géneros podemos registrar un \<font color="#2166ae">género\</font> usando el siguiente fragmento 1 private void addgenre(string name) { 2 //we are taking this name parameter from the input 3 progressdialog show(); 4 parseobject parseobject = new parseobject("genre"); 5 parseobject put("name", name); 6 parseobject saveinbackground(e > { 7 progressdialog dismiss(); 8 if (e == null) { 9 getgenres(); 10 inputgenre settext(""); 11 toast maketext(this, "genre saved successfully", toast length short) show(); 12 } else { 13 toast maketext(this, e getlocalizedmessage(), toast length short) show(); 14 } 15 }); 16 }1 private fun addgenre(name string) { 2 //we are taking this name parameter from the input 3 progressdialog show() 4 val parseobject = parseobject("genre") 5 parseobject put("name", name) 6 parseobject saveinbackground { 7 progressdialog dismiss() 8 if (it == null) { 9 getgenres() 10 inputgenre settext("") 11 toast maketext(this, "genre saved successfully", toast length short) show() 12 } else { 13 toast maketext(this, it localizedmessage, toast length short) show() 14 } 15 } 16 } podemos registrar un \<font color="#2166ae">género\</font> utilizando el siguiente fragmento 1 private void getgenres() { 2 progressdialog show(); 3 parsequery\<parseobject> query = new parsequery<>("genre"); 4 query findinbackground((objects, e) > { 5 progressdialog dismiss(); 6 list\<parseobjectmodel> list = new arraylist<>(); 7 for (parseobject parseobject objects) { 8 list add(new parseobjectmodel(parseobject)); 9 } 10 11 genreadapter adapter = new genreadapter(list, this); 12 recyclerview\ setlayoutmanager(new linearlayoutmanager(this)); 13 recyclerview\ setadapter(adapter); 14 }); 15 }1 private fun getgenres() { 2 progressdialog show() 3 val query = parsequery\<parseobject>("genre") 4 query findinbackground { objects, e > 5 progressdialog dismiss() 6 var list mutablelist\<parseobjectmodel> = arraylist() 7 for (parseobject in objects) { 8 list add(parseobjectmodel(parseobject)) 9 } 10 val adapter = genreadapter(this, list) 11 recyclerview\ layoutmanager = linearlayoutmanager(this) 12 recyclerview\ adapter = adapter 13 } 14 } 1 2 guardar y listar editores podemos registrar un \<font color="#2166ae">editor\</font> utilizando el siguiente fragmento 1 private void addpublisher(string name) { 2 //we are taking this name parameter from the input 3 progressdialog show(); 4 parseobject parseobject = new parseobject("publisher"); 5 parseobject put("name", name); 6 parseobject saveinbackground(e > { 7 progressdialog dismiss(); 8 if (e == null) { 9 getpublishers(); 10 inputpublisher settext(""); 11 toast maketext(this, "publisher saved successfully", toast length short) show(); 12 } else { 13 toast maketext(this, e getlocalizedmessage(), toast length short) show(); 14 } 15 }); 16 }1 private fun addpublisher(name string) { 2 //we are taking this name parameter from the input 3 progressdialog show() 4 val parseobject = parseobject("publisher") 5 parseobject put("name", name) 6 parseobject saveinbackground { 7 progressdialog dismiss() 8 if (it == null) { 9 getpublishers() 10 inputpublisher settext("") 11 toast maketext(this, "publisher saved successfully", toast length short) show() 12 } else { 13 toast maketext(this, it localizedmessage, toast length short) show() 14 } 15 } 16 } podemos registrar un \<font color="#2166ae">editor\</font> utilizando el siguiente fragmento 1 private void getpublishers() { 2 progressdialog show(); 3 parsequery\<parseobject> query = new parsequery<>("publisher"); 4 query findinbackground((objects, e) > { 5 progressdialog dismiss(); 6 list\<parseobjectmodel> list = new arraylist<>(); 7 for (parseobject parseobject objects) { 8 list add(new parseobjectmodel(parseobject)); 9 } 10 11 publisheradapter adapter = new publisheradapter(list, this); 12 recyclerview\ setlayoutmanager(new linearlayoutmanager(this)); 13 recyclerview\ setadapter(adapter); 14 }); 15 }1 private fun getpublishers() { 2 progressdialog show() 3 val query = parsequery\<parseobject>("publisher") 4 query findinbackground { objects, e > 5 progressdialog dismiss() 6 val list arraylist\<parseobjectmodel> = arraylist() 7 for (parseobject in objects) { 8 list add(parseobjectmodel(parseobject)) 9 } 10 11 val adapter = publisheradapter(this, list) 12 recyclerview\ layoutmanager = linearlayoutmanager(this) 13 recyclerview\ adapter = adapter 14 } 15 } 1 3 guardar y listar autores podemos registrar un \<font color="#2166ae">autor\</font> utilizando el siguiente fragmento 1 private void addauthor(string name){ 2 //we are taking this name parameter from the input 3 progressdialog show(); 4 parseobject parseobject = new parseobject("author"); 5 parseobject put("name", name); 6 parseobject saveinbackground(e > { 7 progressdialog dismiss(); 8 if (e == null) { 9 getauthors(); 10 inputauthor settext(""); 11 toast maketext(this, "author saved successfully", toast length short) show(); 12 } else { 13 toast maketext(this, e getlocalizedmessage(), toast length short) show(); 14 } 15 }); 16 }1 private fun addauthor(name string) { 2 //we are taking this name parameter from the input 3 progressdialog show() 4 val parseobject = parseobject("author") 5 parseobject put("name", name) 6 parseobject saveinbackground { 7 progressdialog dismiss() 8 if (it == null) { 9 getauthors() 10 inputauthor settext("") 11 toast maketext(this, "author saved successfully", toast length short) show() 12 } else { 13 toast maketext(this, it localizedmessage, toast length short) show() 14 } 15 } 16 } podemos registrar un \<font color="#2166ae">autor\</font> usando el siguiente fragmento 1 private void getauthors() { 2 progressdialog show(); 3 parsequery\<parseobject> query = new parsequery<>("author"); 4 query findinbackground((objects, e) > { 5 progressdialog dismiss(); 6 list\<parseobjectmodel> list = new arraylist<>(); 7 for (parseobject parseobject objects) { 8 list add(new parseobjectmodel(parseobject)); 9 } 10 11 authoradapter adapter = new authoradapter(list, this); 12 recyclerview\ setlayoutmanager(new linearlayoutmanager(this)); 13 recyclerview\ setadapter(adapter); 14 }); 15 }1 private fun getauthors() { 2 progressdialog show() 3 val query = parsequery\<parseobject>("author") 4 query findinbackground { objects list\<parseobject>, e parseexception? > 5 progressdialog dismiss() 6 val list arraylist\<parseobjectmodel> = arraylist() 7 for (parseobject in objects) { 8 list add(parseobjectmodel(parseobject)) 9 } 10 val adapter = authoradapter(this, list) 11 recyclerview\ layoutmanager = linearlayoutmanager(this) 12 recyclerview\ adapter = adapter 13 } 14 } en esta parte, usamos una clase de modelo llamada \<font color="#2166ae">parseobjectmodel\</font> en esta clase de modelo, tenemos una \<font color="#2166ae">parseobject\</font> variable para poder leer los datos, y la \<font color="#2166ae">ischecked\</font> variable, que usaremos para guardar el libro en el siguiente paso podremos recuperar fácilmente los objetos seleccionados con la \<font color="#2166ae">ischecked\</font> variable aquí está nuestro \<font color="#2166ae">parseobjectmodel\</font> modelo 1 public class parseobjectmodel { 2 parseobject object; 3 boolean ischecked = false; 4 5 public parseobjectmodel(parseobject object) { 6 this object = object; 7 } 8 9 public parseobject getobject() { 10 return object; 11 } 12 13 public parseobjectmodel setobject(parseobject object) { 14 this object = object; 15 return this; 16 } 17 18 public boolean ischecked() { 19 return ischecked; 20 } 21 22 public parseobjectmodel setchecked(boolean checked) { 23 ischecked = checked; 24 return this; 25 } 26 }1 class parseobjectmodel(obj parseobject) { 2 var obj parseobject? = null 3 var ischecked boolean = false 4 5 init { 6 this obj = obj 7 } 8 } 2 guardar un objeto libro y sus relaciones 2 1 guardar un objeto libro con relación 1\ n esta función creará un nuevo \<font color="#2166ae">libro\</font> en la base de datos de back4app con relaciones 1\ n 1 progressdialog show(); 2 book put("genre", genre); 3 book put("publisher", publisher); 4 book put("title", title); 5 book put("year", year); 6 book saveinbackground(e > { 7 progressdialog hide(); 8 if (e == null) { 9 toast maketext(addbookactivity this, "book saved successfully", toast length short) show(); 10 startactivity(new intent(addbookactivity this, booklistactivity class)); 11 finish(); 12 } else { 13 toast maketext(addbookactivity this, e getlocalizedmessage(), toast length short) show(); 14 } 15 });1 progressdialog show() 2 book put("genre", genre) 3 book put("publisher", publisher!!) 4 book put("title", title) 5 book put("year", year) 6 book saveinbackground { 7 progressdialog hide() 8 if (it == null) { 9 toast maketext(this, "book saved successfully", toast length short) show() 10 startactivity(intent(this\@addbookactivity, booklistactivity class java)) 11 finish() 12 } else { 13 toast maketext(this, it localizedmessage, toast length short) show() 14 } 15 } 2 2 guardar un objeto libro con relación n\ n esta función creará un nuevo \<font color="#2166ae">libro\</font> en la base de datos de back4app con relaciones n\ n para la \<font color="#2166ae">autor\</font> relación, encontramos el/los autor/es seleccionados en el adaptador del \<font color="#2166ae">authorrecyclerview\</font> y los guardamos como \<font color="#2166ae">relación parse\</font> 1 progressdialog show(); 2 book put("genre", genre); 3 book put("publisher", publisher); 4 book put("title", title); 5 book put("year", year); 6 7 //here we are setting book relation with getselecteditem function of bookauthoradapter 8 if (recyclerviewauthors getadapter() != null) { 9 relation = ((bookauthoradapter) recyclerviewauthors getadapter()) getselecteditems(book); 10 if (relation == null) { 11 toast maketext(this, "please select author/s", toast length short) show(); 12 return; 13 } 14 } else { 15 toast maketext(this, "something went wrong!!", toast length short) show(); 16 return; 17 } 18 19 book saveinbackground(e > { 20 progressdialog hide(); 21 if (e == null) { 22 toast maketext(addbookactivity this, "book saved successfully", toast length short) show(); 23 startactivity(new intent(addbookactivity this, booklistactivity class)); 24 finish(); 25 } else { 26 toast maketext(addbookactivity this, e getlocalizedmessage(), toast length short) show(); 27 } 28 }); 29 30 //this is the function for save author/s relation of book object this function in bookauthoradapter 31 public parserelation\<parseobject> getselecteditems(parseobject parseobject) { 32 parserelation\<parseobject> relation = parseobject getrelation("author relation"); 33 for (parseobjectmodel object this list) { 34 if (object ischecked()) 35 relation add(object getobject()); 36 } 37 return relation; 38 } 1 progressdialog show() 2 book put("genre", genre) 3 book put("publisher", publisher!!) 4 book put("title", title) 5 book put("year", year) 6 7 //here we are setting book relation with getselecteditem function of bookauthoradapter 8 9 if (recyclerviewauthors adapter != null) { 10 relation = (recyclerviewauthors adapter as bookauthoradapter) getselecteditems(book) 11 if (relation == null) { 12 toast maketext(this, "please select author/s", toast length short) show() 13 return 14 } 15 } else { 16 toast maketext(this, "something went wrong!!", toast length short) show() 17 return 18 } 19 20 book saveinbackground { 21 progressdialog hide() 22 if (it == null) { 23 toast maketext(this, "book saved successfully", toast length short) show() 24 startactivity(intent(this\@addbookactivity, booklistactivity class java)) 25 finish() 26 } else { 27 toast maketext(this, it localizedmessage, toast length short) show() 28 } 29 } 30 31 //this is the function for save author/s relation of book object this function in bookauthoradapter 32 33 fun getselecteditems(parseobject parseobject) parserelation\<parseobject>? { 34 var relation\ parserelation\<parseobject>? = parseobject getrelation("author relation") 35 for (obj in this list) { 36 if (obj ischecked) 37 relation? add(obj obj) 38 } 39 return relation 40 } 3 consultar los detalles del libro con relaciones con estas funciones, listaremos nuestros \<font color="#2166ae">libros\</font> de acuerdo a sus \<font color="#2166ae">editoriales\</font> primero, lanzamos una consulta a la clase publisher 1 progressdialog show(); 2 parsequery\<parseobject> query = new parsequery<>("publisher"); 3 query findinbackground((objects, e) > { 4 progressdialog hide(); 5 if (e == null) { 6 booklistadapter adapter = new booklistadapter(objects, this); 7 recyclerview\ setlayoutmanager(new linearlayoutmanager(this)); 8 recyclerview\ setadapter(adapter); 9 } else { 10 toast maketext(this, e getlocalizedmessage(), toast length short) show(); 11 } 12 });1 progressdialog show() 2 val query = parsequery\<parseobject>("publisher") 3 query findinbackground { objects list\<parseobject>?, e parseexception? > 4 progressdialog hide() 5 if (e == null) { 6 val adapter = booklistadapter(this, objects!!) 7 recyclerview\ layoutmanager = linearlayoutmanager(this) 8 recyclerview\ adapter = adapter 9 } else { 10 toast maketext(this, e localizedmessage, toast length short) show() 11 } 12 } y luego consultamos para listar los \<font color="#2166ae">libros\</font> a los que cada \<font color="#2166ae">editor\</font> está relacionado 1 parseobject object = list get(position); 2 holder title settext(object getstring("name")); 3 parsequery\<parseobject> query = new parsequery<>("book"); 4 query whereequalto("publisher", object); 5 query findinbackground((objects, e) > { 6 if (e == null) { 7 booksadapter adapter = new booksadapter(objects, context); 8 holder books setlayoutmanager(new linearlayoutmanager(context)); 9 holder books setadapter(adapter); 10 } else { 11 toast maketext(context, e getlocalizedmessage(), toast length short) show(); 12 } 13 });1 val `object` = list\[position] 2 holder title text = `object` getstring("name") 3 val query = parsequery\<parseobject>("book") 4 query whereequalto("publisher", `object`) 5 query findinbackground { objects list\<parseobject>?, e parseexception? > 6 if (e == null) { 7 val adapter = booksadapter(context, objects!!) 8 holder books layoutmanager = linearlayoutmanager(context) 9 holder books adapter = adapter 10 } else { 11 toast maketext(context, e localizedmessage, toast length short) show() 12 } 13 } ahora, cuando hacemos clic en cualquier \<font color="#2166ae">libro\</font> objeto, enviamos el id del objeto de este \<font color="#2166ae">libro\</font> con una intención a la página que mostrará los detalles de ese \<font color="#2166ae">libro\</font> y obtenemos todos los detalles del \<font color="#2166ae">libro \</font> de la base de datos utilizando este id de objeto en esa página 1 private void getbookwithdetails() { 2 progressdialog show(); 3 parsequery\<parseobject> query = new parsequery<>("book"); 4 query getinbackground(getintent() getstringextra("objectid"), (object, e) > { 5 if (e == null) { 6 booktitle settext("title " +object getstring("title")); 7 bookyear settext("year " +object getstring("year")); 8 try { 9 bookgenre settext("genre " +object getparseobject("genre") fetchifneeded() getstring("name")); 10 } catch (parseexception parseexception) { 11 parseexception printstacktrace(); 12 } 13 try { 14 bookpublisher settext("publisher " + object getparseobject("publisher") fetchifneeded() getstring("name")); 15 } catch (parseexception parseexception) { 16 parseexception printstacktrace(); 17 } 18 19 object getrelation("author relation") getquery() findinbackground((objects, e1) > { 20 progressdialog hide(); 21 if (e1 == null) { 22 bookdetailauthoradapter adapter = new bookdetailauthoradapter(objects, this); 23 authorrecyclerview\ setlayoutmanager(new linearlayoutmanager(this)); 24 authorrecyclerview\ setadapter(adapter); 25 } else { 26 toast maketext(this, e getlocalizedmessage(), toast length short) show(); 27 } 28 }); 29 } else { 30 progressdialog hide(); 31 toast maketext(this, e getlocalizedmessage(), toast length short) show(); 32 } 33 }); 34 }1 private fun getbookwithdetails() { 2 progressdialog show() 3 val query = parsequery\<parseobject>("book") 4 5 query getinbackground(intent getstringextra("objectid")) { `object`, e > 6 if (e == null) { 7 booktitle text = "title " + `object` getstring("title") 8 bookyear text = "year " + `object` getstring("year") 9 try { 10 bookgenre text = "genre " + `object` getparseobject("genre")? fetchifneeded\<parseobject>()? getstring("name") 11 } catch (parseexception parseexception) { 12 parseexception printstacktrace() 13 } 14 try { 15 bookpublisher text = 16 "publisher " + `object` getparseobject("publisher")? fetchifneeded\<parseobject>()? getstring("name") 17 } catch (parseexception parseexception) { 18 parseexception printstacktrace() 19 } 20 21 `object` getrelation\<parseobject>("author relation") query findinbackground { objects, e1 > 22 progressdialog hide() 23 if (e1 == null) { 24 val adapter = bookdetailauthoradapter(this, objects) 25 authorrecyclerview\ layoutmanager = linearlayoutmanager(this) 26 authorrecyclerview\ adapter = adapter 27 } else { 28 toast maketext(this, e1 localizedmessage, toast length short) show() 29 } 30 } 31 } else { 32 progressdialog hide() 33 toast maketext(this, e localizedmessage, toast length short) show() 34 } 35 } 36 } ¡está hecho! en este punto, hemos aprendido \<font color="#2166ae">relaciones de parse\</font> en \<font color="#2166ae">android\</font>