https://github.com/realm/realm-java
In Today's tutorial, we are going to continue learning about queries in Realm. The first part of this tutorial can be found here
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.
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.
SingleQuery.java class file.PatternMatching fragment.Please refer to the first tutorial for the dependencies used in this tutorial
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>
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" />
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.
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.
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.
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.
We add the FragmentTransaction codes inside the showFragment() method
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.
SingleQuery.java class fileIn 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.
toDisplay object.For every predicate we use, we are going to be appending the name of that predicate to the toDisplay object -
Modifications
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");
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");
endsWith() and equalTo() predicatesThe 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++;
}
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 -
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.
PatternMatching fragmentWe are going to illustrating the like() predicate in the PatternMatching Fragment.
Firslty, we will include two TextViews 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.
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"
/>
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.
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());
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();
}
https://github.com/generalkolo/Realm-JSON/tree/master/Realm%20Relationships