Understanding Queries in Realm Java using Android Studio (PART 2)

in #utopian-io6 years ago

realmDark.jpg

Repository

https://github.com/realm/realm-java

What Will I Learn?

  1. 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

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.

BlankFragment1.PNG

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.

PatternMatching.PNG

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

  1. 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");

  1. 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 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.

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

Sort:  

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:

  • Improve the structure of the tutorial.

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.

Coin Marketplace

STEEM 0.18
TRX 0.14
JST 0.029
BTC 58051.31
ETH 3136.86
USDT 1.00
SBD 2.44