Relationships
19 min
relationships on android introduction using parse, you can store data objects establishing relations between them to model this behavior, any \<font color="#2166ae">parseobject\</font> can be used as a value in other \<font color="#2166ae">parseobject\</font> internally, the parse framework will store the referred to object in just one place, to maintain consistency that can give you extra power when building and running complex queries there are three main relation types \<font color="#2166ae">one to one\</font> , establishing direct relations between two objects and only them; \<font color="#2166ae">one to many\</font> , where one object can be related to many other objects; \<font color="#2166ae">many to many\</font> , which can create many complex relations between many objects there are two ways to create a \<font color="#2166ae">one to many\</font> relation in parse the first is using the \<font color="#2166ae">pointers\</font> in \<font color="#2166ae">child class,\</font> which is the fastest in creation and query time the second is using \<font color="#2166ae">arrays\</font> of \<font color="#2166ae">pointers\</font> in parent class which can lead to slow query times depending on their size because of this performance issue, we will use only pointers examples there are three ways to create a \<font color="#2166ae">many to many\</font> relation in parse the first is using the parse \<font color="#2166ae">relations\</font> , which is the fastest in creation and query time we will use this in this guide the second is using \<font color="#2166ae">arrays\</font> of \<font color="#2166ae">pointers\</font> which can lead to slow query times depending on their size the third is using \<font color="#2166ae">jointable\</font> where the idea from classical database when there is a many to nany relation, we combine every \<font color="#2166ae">objectid\</font> or \<font color="#2166ae">pointer\</font> from both sides together to build a new separate table in which the relationship is tracked this tutorial uses a basic app created in android studio 4 1 1 with \<font color="#2166ae">buildtoolsversion=30 0 2\</font> , \<font color="#2166ae">compile sdk version = 30 0 2\</font> and \<font color="#2166ae">targetsdkversion 30\</font> at any time, you can access the complete android project built with this tutorial at our github repositories kotlin example repository https //github com/templates back4app/android parse sdk kotlin java example repository https //github com/templates back4app/android parse sdk java goal our goal is, understand parse relations by creating a practical book app here is a preview of what we are gonna achieve prerequisites to complete this tutorial, we need android studio https //developer android com/studio/index html an app created on back4app note follow the new parse app tutorial https //www back4app com/docs/get started/new parse app to learn how to create a parse app on back4app an android app connected to back4app note follow the install parse sdk tutoria https //www back4app com/docs/android/parse android sdk l to create an android studio project connected to back4app a device (or virtual device https //developer android com/studio/run/managing avds html ) running android 4 1 (jelly bean) or newer understanding the book app the main object class you’ll be using is the \<font color="#2166ae">book\</font> class, storing each book entry in the registration also, these are the other three object classes \<font color="#2166ae">publisher\</font> book publisher name, \<font color="#2166ae">one to many\</font> relation with \<font color="#2166ae">book\</font> \<font color="#2166ae">genre\</font> book genre, \<font color="#2166ae">one to many\</font> relation with \<font color="#2166ae">book\</font> note that for this example we will consider that a book can only have one genre; \<font color="#2166ae">author\</font> book author, \<font color="#2166ae">many to many\</font> relation with \<font color="#2166ae">book\</font> , since a book can have more than one author and an author can have more than one book as well; a visual representation of these data model let’s get started! before next steps, we need to connect \<font color="#2166ae">back4app\</font> to our application you should save the \<font color="#2166ae">appid\</font> and \<font color="#2166ae">clientkey\</font> from the \<font color="#2166ae">back4app\</font> to \<font color="#2166ae">string xml\</font> file and then init \<font color="#2166ae">parse\</font> in our \<font color="#2166ae">app java\</font> or \<font color="#2166ae">app kt\</font> file follow the new parse app tutorial https //www back4app com/docs/android/parse android sdk if you don’t know how to init \<font color="#2166ae">parse\</font> to your app or you can download the projects we shared the github links above and edit only the \<font color="#2166ae">appid\</font> and \<font color="#2166ae">clientkey\</font> parts according to you 1 save and list related objects of books in this step we will see how to save and list the \<font color="#2166ae">genres\</font> , \<font color="#2166ae">publishers\</font> and \<font color="#2166ae">authors\</font> classes related with the \<font color="#2166ae">book\</font> class 1 1 save and list genres we can register a \<font color="#2166ae">genre\</font> using the following snippet 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 } we can register a \<font color="#2166ae">genre\</font> using the following snippet 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 save and list publishers we can register a \<font color="#2166ae">publisher\</font> using the following snippet 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 } we can register a \<font color="#2166ae">publisher\</font> using the following snippet 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 save and list authors we can register a \<font color="#2166ae">author\</font> using the following snippet 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 } we can register a \<font color="#2166ae">author\</font> using the following snippet 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 } in this part, we use a model class named \<font color="#2166ae">parseobjectmodel\</font> in this model class, we have a \<font color="#2166ae">parseobject\</font> variable to be able to read the data, and the \<font color="#2166ae">ischecked\</font> variable, which we will use to save the book in the next step we will be able to easily retrieve the selected objects with the \<font color="#2166ae">ischecked\</font> variable here is the our \<font color="#2166ae">parseobjectmodel\</font> model 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 save a book object and its relations 2 1 save a book object with 1\ n relationship this function will create a new \<font color="#2166ae">book\</font> in back4app database with 1\ n relations 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 save a book object with n\ n relationship this function will create a new \<font color="#2166ae">book\</font> in back4app database with n\ n relations for the \<font color="#2166ae">author\</font> relation, we find the selected author/s in the adapter of the \<font color="#2166ae">authorrecyclerview\</font> and save them as \<font color="#2166ae">parse relation\</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 query the book details with relations with these functions, we will list our \<font color="#2166ae">books\</font> according to their \<font color="#2166ae">publishers\</font> first, we throw a query to the publisher class 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 } and then we query to list the \<font color="#2166ae">books\</font> that each \<font color="#2166ae">publisher\</font> item is related to 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 } now, when we click on any \<font color="#2166ae">book\</font> object, we send the object id of this \<font color="#2166ae">book\</font> with an intent to the page that will show the details of that \<font color="#2166ae">book\</font> and we get all the details of the \<font color="#2166ae">book \</font> from the database by using this object id on that page 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 } it’s done! at this point, we have learned \<font color="#2166ae">parse relationships\</font> on \<font color="#2166ae">android\</font>