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

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
  • between() predicate
  • greaterThan() predicate
  • lessThan() predicate
  • greaterThanOrEqualTo() predicate
  • greaterThanOrEqualTo() 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 and second part of this tutorial series can he found here and (here)[] respectively.

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.

Recap of Part 2

In the part two of this tutorial series, we looked at the - beginsWith(), endsWith(),like() predicates.

The beginsWith() predicate checks to ensure that an object's field begins with the query string passed as a second argument to it and then it also takes the optional third case argument - Case.SENSITIVE or Case.INSENSITIVE, while the endsWith() predicate does the opposite of the beginsWith() predicate where it checks to ensure that an object's field ends with the query string passed as the second argument to it, and it also takes the third optional case argument.

Meanwhile, the like() predicate performs a glob style wildcard matching with the following :

  • ? matches a single unicode character
  • * matches 0 or more unicode characters.

Todays Tutorials

In todays tutorial, we are going to be learning about more query predicates in Realm, we are going to be learning about - between(), greaterThan(), lessThan(), greaterThanOrEqualTo() and `lessThanOrEqualTo() predicates.

And in order to achieve this, we are going to be modyfying our already exisiting android application to include two more fragments, where fragmanet one -DoubleNumericQuery will illustrate the use of the first listed predicate and the second - NumericQuery will illustrate the remaining four listed predicates.

Outline

  • Dependencied Used
  • Add Two new Buttons in activity_main Layout
  • Create Two new Fragments
  • Add FragmentTransaction codes in MainActivity.java
  • Show Predicate Illustration in respective fragment

Depenedencies used

Please refer to the first tutorial for the dependencies used in this tutorial as no new dependencies has been added

Add Two new Buttons in activity_main Layout

We are going to add two new buttons to our activity_main.xml file inwhich when the user clicks, we are going to call the appropriate fragments which we will be creating later in this tutorial.

NB: The xml code below will only feature new additions to the layout file and other exisiting views will be indicated in comments - //

activity_main.xml

//Root RelativeLayout
 //LinearLayout with vertical orientation
  // Four already existing buttons
<Button
android:id="@+id/numeric_string_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Numeric Query" />

<Button
android:id="@+id/double_numeric_string_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Double Numeric Query" />

Create Two new Fragments

We will be creating two new fragment which we will be using illustrate the uses of the predicates.

To create a new blank fragment, right click on your java folder => New => Fragment => Blank Fragment.

BlankFragment1.PNG

Next, Name your fragment - DoubleNumericQuery and then do not forget to uncheck the - Include fragment factory methods ? and include interface callbacks checkboxes.

---- Image of DoubleNumericFragment

Create another Fragment the same way and name it - NumericQuery

Add Fragment Transactions in MainActivity.java class

Next, in our mainActivity.java we will be using butterknife to inject the onClick() method for our two newly added buttons 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
    ,R.id.numeric_string_query,R.id.double_numeric_string_query})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            // already existing four cases
            case R.id.numeric_string_query:
                showNumericQueryFragment();
                break;
            case R.id.double_numeric_string_query:
                showDoubleNumericQueryFragment();
                break;
        }
    }

NB: The showNumericQueryFragment() and showDoubleNumericQueryFragment() wasn't added by butterknife.

showDoubleNumericQueryFragment()

private void showDoubleNumericQueryFragment() {
        DoubleNumericQuery doubleNumericQuery = new DoubleNumericQuery();
        showFragment(doubleNumericQuery);
}

In this method, we create a DoubleNumericQuery 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.

NB: 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.

Show Predicate Usage in respective fragment

DoubleNumericQuery

In our DoubleNumericQuery Fragment, we are going to be learning the between() predicate. The between() predicate, takes three arguments -

  • the name of the field to be queried.
  • the lowest value of the query
  • the highest value of the query

The between() checks for objects that the specified field is between a given range, specified by the second and third argument.

We are going to be querying the age field in our Person class and then we will be accept two ages from the user which will be used in our between() predicate.
We therefore are going to be creating two EditText's, a button and two TextView's in our DoubleNumericQuery Fragment layout file - double_numeric_query_fragment.xml.

  • The EditText's will be used to accept the two ages
  • The Button will be used to start the query
  • One of the TextViews will display the text - Result and the other will be used to display the result of the query
//ScroolView RootLayout
  //RelativeLayout
<EditText
android:layout_marginTop="30dp"
android:id="@+id/query_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="Enter First Age" />

<EditText
android:layout_below="@+id/query_name"
android:id="@+id/query_name_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="Enter Second Age" />

<Button
android:id="@+id/go_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/query_name_2"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="GO" />

<TextView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/go_btn"
android:layout_marginTop="30dp"
android:gravity="center_horizontal"
android:text="Result Will appear Here"
android:textColor="#000"
android:textSize="18sp" />

In our DoubleNumericQuery java class file, we have to declear a ralm variable - private Realm realm and then get a default instance with the line - realm = Realm.getDefaultInstance();
Next, we use inject our two EditText and an onClick() method for our GO button using ButterKnife and in the onClick method we include the following codes -

String age = queryName.getText().toString();
String age2 = queryName2.getText().toString();

StringBuilder toDisplay = new StringBuilder();

if ((!(age.isEmpty() && age2.isEmpty()))&& (Integer.valueOf(age2) > Integer.valueOf(age))) {

    RealmResults<Person> result = realm.where(Person.class)
            .between("age", Integer.valueOf(age),Integer.valueOf(age2))
            .findAll();

    toDisplay.append("between() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons between " + age + " and "+age2+"\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 + " Address :" + result.get(i).address + " and age : "+ result.get(i).age +"\n\n\n");
        i++;
    }
    resultTv.setText(toDisplay.toString());
}

else
    showToast("No Field can be Empty and First Age must be greater than Second Age");

Code Explanation

  1. We get the value of the two EditText's and store in string variables - age and age2.
  2. We declear a StringBuilder object - toDisplay
  3. We use an if statement to ensure that the age and age2 variables are not empty and also that the age2 variable is greater than the age varibale else we simply call the showToast() method with the argument -"No Field can be Empty and First Age must be greater than Second Age".
  4. We create a RealmResult object - result and then we use the between() predicate with the where statment specifying the Person class and then setting the lower and upper bound values of the between() predicate to be age and age2.
  5. We append the text - between() predicate and also append the size of the objects that is returned by the query by - result.size() and append the age and age2 values.
  6. We then use a while loop to loop through the objects that match our query and then dispay the details of each object.
    • name : result.get(i).name
    • phone number : result.get(i).phone_number
    • email : result.get(i).email
    • address : result.get(i).address
    • age : result.get(i).age
  7. We then display our result in our TextView - resultTv.setText(toDisplay.toString());

NumericQuery

In our NumericQuery Fragment, we are going to be learning the greaterThan(), lessThan(),greaterThanOrEqualTo(),lessThanOrEqualTo predicates. They all take two arguments, one being the field name and second the query string :

  • greaterThan() checks for objects that the specified field is has a value greater than the query string.
  • lessThan() checks for objects that the specified field is has a value lesser than the query string.
  • greaterThanOrEqualTo() checks for objects that the specified field is has a value greater or equal to the query string.
  • lessThanOrEqualTo() checks for objects that the specified field is has a value lesser or equal to the query string.
    NB: We are also going to be querying the age field in our Person class.

In our NumericQuery Fragment layout file - numeric_query_fragment.xml we will be adding one EditText, one Button and Two TextView's.

  • EditText to accept the query string from the user.
  • Button for the beginning the query search.
  • One TextView for dsiplaying the text - "Result" and one TextView for displaying the result gotten from the queries.
//ScrollView RootLayout
 //LinearLayout with vertical orientation
<EditText
android:id="@+id/query_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:inputType="number"
android:hint="Enter Age" />

<Button
android:id="@+id/go_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/query_name"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="GO" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Result"
android:textSize="16sp" />

<TextView
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/go_btn"
android:layout_marginTop="30dp"
android:gravity="center_horizontal"
android:text="Result Will appear Here"
android:textColor="#000"
android:textSize="18sp" />

In our NumericQuery java class file, we have to declear a ralm variable - private Realm realm and then get a default instance with the line - realm = Realm.getDefaultInstance();
Next, we use inject our two EditText and an onClick() method for our GO button using ButterKnife and in the onClick method we include the following codes -

String age = queryName.getText().toString();

StringBuilder toDisplay = new StringBuilder();

if (!age.isEmpty()) {
    RealmResults<Person> result = realm.where(Person.class)
            .greaterThan("age", Integer.valueOf(age))
            .findAll();

    toDisplay.append("greaterThan() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons older than " + age + "\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 + " Address :" + result.get(i).address + " and age : "+ result.get(i).age +"\n\n\n");
        i++;
    }

    result = realm.where(Person.class)
            .lessThan("age",Integer.valueOf(age))
            .findAll();

    toDisplay.append("lessThan() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons younger than " + age + "\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+ " and age : "+ result.get(i).age +"\n\n\n");
        i++;
    }

    result = realm.where(Person.class)
            .greaterThanOrEqualTo("age",Integer.valueOf(age))
            .findAll();

    toDisplay.append("greaterThanOrEqualTo() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons older than " + age + " or "+age+" years old"+"\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+ " and age : "+ result.get(i).age +"\n\n\n");
        i++;
    }

    result = realm.where(Person.class)
            .lessThanOrEqualTo("age",Integer.valueOf(age))
            .findAll();

    toDisplay.append("lessThanOrEqualTo() Predicate\n\n");
    toDisplay.append("There are - " + result.size() + " Persons younger than " + age + " or "+age+" years old"+"\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+ " and age : "+ result.get(i).age +"\n\n\n");
        i++;
    }
    resultTv.setText(toDisplay.toString());
}
else
    showToast("Age Field cannot be empty");

Code Explanation

  1. We get the string entered by the user in our EditText and we save it in the string variable - age
  2. We declear a StringBuilder object - toDisplay.
  3. We then check to ensure that age variable is not empty.
  4. We then declear a ReamlResults object - result and then we use the greaterThan() predicate with the where statment specifying the Person class and then passing the age field as the firsy argument and the query string as the second argument.
  5. We append the text - greaterThan() predicate and also append the size of the objects that are returned by the query by - result.size().
  6. We then use a while loop to loop through the objects that match our query and then display the details of each object.
    • Same Explanation applies for the lessThan(),greaterThanOrEqualTo() and lessThanOrEqualTo() predicates.
  7. We then set the text of the TextView that shows the result of the query in the line - 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:  

Thankyou for your kinds and for a good tutorials....
You are the best... Good luck @edetebenezer

You most welcome and am glad you like it @asrinaphonna.
Stay tuned theres more tutorials coming

Thank you for the contribution! Nice tutorial, as always.

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 @deathwing for moderating.
Thanks for the complement too.
Keep up the good work 👍

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!

Thankyou for your kinds and for a good tutorials....
You are the best... Good luck

Thankyou for your kinds and for a good tutorials....
You are the best... Good luck @edetebenezer

Coin Marketplace

STEEM 0.20
TRX 0.14
JST 0.029
BTC 67900.86
ETH 3250.85
USDT 1.00
SBD 2.63