Repository
https://github.com/realm/realm-java
What Will I Learn?
- You will learn about Queries in Realm
- equalTo() predicate
- endsWith() predicate
- like() predicate
Requirements
- An Integrated Development Environment(IDE) for building Android Application(e.g Android Studio, IntelliJ)
- Android Device/Virtual Device.
- Little Experience in working with Realm Java.
- Java Programming Experience.
- Of course, willingness to learn
Resources
- Retrofit Website. https://realm.io/
- Retrofit Github. - https://github.com/realm
- Retrofit License - Apache License
- Lombok Project - https://projectlombok.org/
Difficulty
- Intermediate
Tutorial Duration - 30 - 35Mins
Tutorial Content
In Today's tutorial, we are going to continue learning about queries in Realm. The first part of this tutorial can be found here
Recap of Part 1
In part 1 of this tutorial, we looked at three predicates - contains()
,beginsWith()
,in()
and we were able to understand this by creating an android application that demonstrates the uses of this predicates.
We learnt that predicates that the form of `predicateName("field","query string",OPTIONAL ARGUMENT);
e.g - contains("name","Edet Ebenezer",Case.SENSITIVE);
The above code checks if any object's name field contains the text - Edet Ebenezer
without paying attention to the cases.
We also learned how to use the third optional argument for the predicates which are Case.INSENSITIVE
and Case.SENSITIVE
where the former ignores the case of the query string to the contents of the field specified and the latter doesn't ignore it.
Todays Tutorials
In today tutorials, we are going to be modifying our exisiting android application, we will be adding one more fragment - PatternMatching
and then we will be modifying our SingleQuery
java class file to show case the use of - endsWith() and equalTo()
predicates.
We are also going to be modifing our SingleQuery.java
class file inorder to make the result display more detailed.
Lastly, we are going to also be modifying our layout file - single_query.xml
to make the parent layout a ScrollView
rather than the former RelativeLayout
.
Outline
- Dependencied Used.
- Modify single_query_fragment.xml file.
- Add One Button in activity_main Layout
- Create One Fragment.
- Add FragmentTransaction codes in MainActivity.java
- Edit
SingleQuery.java
class file. - Show Predicate Illustration in
PatternMatching
fragment.
Depenedencies used
Please refer to the first tutorial for the dependencies used in this tutorial
Modify single_query_fragment.xml file
We intend to add two predicates to our SingleQuery
Fragment, so inorder to make the layout flow well, we are going to be changing our root layout element to a ScrollView
and then we are going to be adding an extra TextView
below the GO
button to only display the text - Result
single_query_fragment modifications
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFF"
tools:context=".SingleQuery">
//...LinearLayout, EditText and Go Button
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Result"
android:textSize="16sp" />
//..TextView with id - result to show the result from querying
</LinearLayout>
</ScrollView>
Add One Button in activity_main Layout
To show the like()
predicate, we are going to be using a fragment - MultipleStringQuery
which will be called once the user clicks on a button.
We need to add that button to our activity_main.xml
layout file, the button will display have the text -Pattern Matching Query
and have the id of - pattern_string_query
which will be specified using the android:text
property.
Modifications to the activity_main.xml
//...RelativeLayout Root View with id - mainLayout
//... LinearLayout with orientation - veritcal
//...Three already existing buttons
<Button
android:id="@+id/pattern_string_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pattern Matching Query" />
Create One Fragment
We will be creating one fragment which we will be using demonstrate the use of the like()
predicate.
To create a new blank fragment, right click on your java folder => New => Fragment => Blank Fragment.
Next, Name your fragment - SingleQuery
and then do not forget to uncheck the - Include fragment factory methods ?
and include interface callbacks
checkboxes the name of the fragment will be PatternMatching
.
Add Fragment Transactions in MainActivity.java class
Next, in our mainActivity.java we will be using butterknife to inject the onClick method newly added button and we will be using FragmentTransaction to call the appropriate fragment based on the button that was clicked.
To inject the onClick methods of the new buttons using butterknife, place your cursor on the layout name on the setContentView()
method and then on windows - alt + ins => Generate ButterKnife Injection and then select the checkboxes.
Injected Code
The MainActivity.java class file should now look like this
@OnClick({R.id.single_query, R.id.double_string_query, R.id.multiple_string_query,R.id.pattern_string_query})
public void onViewClicked(View view) {
switch (view.getId()) {
//... already existing three cases
case R.id.pattern_string_query:
showPatternQueryFragment();
break;
}
}
Note: The showPatternQueryFragment()
wasn't added by butterknife.
showPatternQueryFragment()
private void showPatternQueryFragment() {
PatternMatching patternMatching = new PatternMatching();
showFragment(patternMatching);
}
In this method, we create a PatternMatching
Fragment object and then pass it as an argument to the showFragment()
method.
Add FragmentTransaction codes in MainActivity.java
We add the FragmentTransaction codes inside the showFragment()
method
showFragment()
private void showFragment(Fragment fragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.mainLayout,fragment).addToBackStack(fragment.getTag());
ft.commit();
}
Firstly, we get a FragmentManager
object and set it to the getFragmentManger()
and then we get a FragmentTransaction
object - ft
and begin a transaction with it on the FragmentManager
object - fragmentManager
.
We then call the replace method on the FragmentTransaction
object passing the id of the view we want replaced and the the fragment to replace it as the arguments.
Note: The mainLayout
id is the id of the RelativeLayout
which is the root layout for our activity_main.xml
file.
We then add the fragment to backStack using the addToBackStack()
method and getting the tag from the fragment as the argument and finally we call commit()
on the transaction.
Edit SingleQuery.java
class file
In our SingleQuery.java
class file, we are going to be adding the endsWith()
and equalTo
predicates, which we will be including in our exisiting onClick
method for the GO
button which we already injected in part 1 using ButterKnife
.
We then will make some modifications to our StringBuilder
object - toDisplay
which holds the text we display to the user once we have queried the Realm
database for the nessesary conditions using predicates.
Modification to toDisplay
object.
For every predicate we use, we are going to be appending the name of that predicate to the toDisplay
object -
Modifications
- For the contains() predicate -
RealmResults<Person> result = realm.where(Person.class)
.contains("name", string_queryName, Case.INSENSITIVE)
.findAll();
toDisplay.append("contains() Predicate\n\n"); // appended the text - "contains() Predicate"
toDisplay.append("There are - "+result.size()+" Persons with a name like that\n\n");
- For beginsWith() predicate -
result = realm.where(Person.class)
.beginsWith("name",string_queryName,Case.SENSITIVE)
.findAll();
toDisplay.append("beginsWith() Predicate\n\n"); // appended the text - "beginsWith() Predicate"
toDisplay.append("There are - "+result.size()+" Persons that their name starts with - "+string_queryName+"\n\n");
Addition of endsWith()
and equalTo()
predicates
endsWith()
The endsWith()
predicate checks if the field specified ends with the query string passed to it, in this illustration, we are going to be using the name
field from our Person
class and pass the query entered by the user which is stored in the string variable - string_queryName
and the optional argument of Case.SENSITIVE
which indicates that cases should match.
In our SingleQuery
Fragment, we add the following code below the `startsWith() predicate code block
toDisplay.append("endsWith() Predicate\n\n");
result = realm.where(Person.class)
.endsWith("name",string_queryName,Case.SENSITIVE)
.findAll();
toDisplay.append("endsWith() Predicate\n\n"); // appended the text - "endsWith() Predicate"
toDisplay.append("There are - "+result.size()+" Persons that their name ends with - "+string_queryName+"\n\n");
i = 0;
while(i < result.size()){
toDisplay.append(result.get(i).name+" with phone number : "+result.get(i).phone_number+" email : "+result.get(i).email+" and Address : "+result.get(i).address+"\n\n\n");
i++;
}
Code Explanation
We initialize the result
object which is a RealmResult
object and set it to the objects that their name
field ends with the query string entered by the user.
We use a where loop to loop through all the objects that match the search and then we get the following details -
- name : result.get(i).name
- phone number : result.get(i).phone_number
- email : result.get(i).email
- address : result.get(i).address
equalTo()
And below the above code, we add the equalTo()
predicate which checks that the query string matches exactly the field specified.
The equalTo()
predicate ensure that there is a perfect match for the query string and the field specified.
toDisplay.append("equalTo() Predicate\n\n");
result = realm.where(Person.class)
.equalTo("name",string_queryName,Case.INSENSITIVE)
.findAll();
toDisplay.append("There are - "+result.size()+" Persons match the name - "+string_queryName+"\n\n");
i = 0;
while(i < result.size()){
toDisplay.append(result.get(i).name+" with phone number : "+result.get(i).phone_number+" email : "+result.get(i).email+" and Address : "+result.get(i).address+"\n\n\n");
i++;
}
We use the RealmResult
object - result
once again to check the Person
class objects to find out objects that their name
field matches exactly the query strinig including their cases.
We firstly append the predicate being used here, then we append the size of the number of objects that match the search and then we display the details as explained above in the - endsWith()
predicate.
Show Predicate Illustration in PatternMatching
fragment
We are going to illustrating the like()
predicate in the PatternMatching
Fragment.
Firslty, we will include two TextView
s in our pattern_matching_fragment
layout file , one for showing the text - Result
and then the other for displaying the result gotten from the query.
Adding Two TextViews
The below codes add two TextViews
to the pattern_matching_fragment
layout file -
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Result"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:id="@+id/result"
android:text="Result will appear here"
android:textSize="17sp"
android:textColor="#000"
/>
Adding like()
predicate.
In the PatternMatching.java
class file, we are going to add the like()
predicate in the onCreate()
method, the like predicate, peforms a glob-style wildcard matching. Matching the patteren consists of characters and one or more wildcards.
- Matches 0 or more unicode characters
- ? Matches a single unicode character.
We first have to declear a Realm
variable and initialize it to a defaultInstance - private Realm realm
and realm = Realm.getDefaultInstance()
.
Inside our onCreate()
method we make a call to an initViews()
method where we ultilize the like()
predicate as follows -
StringBuilder toDisplay = new StringBuilder();
String pattern = "?det*";
RealmResults<Person> result = realm.where(Person.class)
.like("name", pattern, Case.INSENSITIVE)
.findAll();
toDisplay.append("like() Predicate\n"); // append the text - like() Predicate
toDisplay.append("Pattern - "+pattern+"\n");
toDisplay.append("There are - "+result.size()+" Person's name that match the pattern - "+pattern+"\n\n");
int i = 0;
while(i < result.size()){
toDisplay.append(result.get(i).name+" with phone number : "+result.get(i).phone_number+" email : "+result.get(i).email+" and Address : "+result.get(i).address+"\n\n\n");
i++;
}
pattern = "*Jo*";
result = realm.where(Person.class)
.like("name", pattern, Case.INSENSITIVE)
.findAll();
toDisplay.append("Pattern - "+pattern+"\n\n");
toDisplay.append("There are - "+result.size()+" Person's name that match the pattern - "+pattern+"\n\n");
i = 0;
while(i < result.size()){
toDisplay.append(result.get(i).name+" with phone number : "+result.get(i).phone_number+" email : "+result.get(i).email+" and Address : "+result.get(i).address+"\n\n\n");
i++;
}
pattern = "*gmail.com";
result = realm.where(Person.class)
.like("email", pattern, Case.INSENSITIVE)
.findAll();
toDisplay.append("Pattern - "+pattern+"\n\n");
toDisplay.append("There are - "+result.size()+" Person's with email with the pattern - "+pattern+"\n\n");
i = 0;
while(i < result.size()){
toDisplay.append(result.get(i).name+" with phone number : "+result.get(i).phone_number+" email : "+result.get(i).email+" and Address : "+result.get(i).address+"\n\n\n");
i++;
}
resultTV.setText(toDisplay.toString());
Code Explanation
The string variable - pattern
is used to stored the pattern we pass to the like()
pattern.
Firstly, the first pattern - "?det*"
matches any string that has a single character before the letters - det
and any number of characters after.
Secondly, the next pattern - *Jo*
matches any string that has any number of character before the characters Jo
and then any number of precedding characters.
And the last pattern - *gmail.com
macthes any string that has any number of characters before the characters -gmail.com
and no other precedding characters.
And then we finally display the result in the TextView
reference - resultTV
that was injected with ButterKnife
- resultTV.setText(toDisplay.toString());
.
NB: we must always close the realm database in the onDestroy()
method as shown below -
@Override
public void onDestroyView() {
super.onDestroyView();
realm.close();
}
Application Execution
Curriculum
Complete Source code:
https://github.com/generalkolo/Realm-JSON/tree/master/Realm%20Relationships
Hey @edetebenezer
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!
Thank you for your contribution.
While I liked the content of your contribution, I would still like to extend one advice for your upcoming contributions:
Looking forward to your upcoming tutorials.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Thanks @portugalcoin for taking time to moderate my contribution.
Improvements will be made on subsequent contributions
Really great tutorial, but I would like to ask, what type of screen recording software you are using
Hi @leczy I use the inbuilt snipping tool on windows. You can get that by clicking your windows button and searching for snipping tools then lunch by pressing enter then click on the new button then draw your mouse over the screen you want captured.