Click here to Skip to main content
15,885,546 members
Articles / Mobile Apps / Android

Create Your First Android App – Part 3

Rate me:
Please Sign up or sign in to vote.
4.71/5 (3 votes)
13 Jul 2015CPOL10 min read 20K   8   1
CodeProject This post is part 3 of a three part Android development tutorial series where I provide a walk-through on how to create and publish your first Android app.

This post is part 3 of a three part Android development tutorial series where I provide a walk-through on how to create and publish your first Android app. There are three post in this series

Post 1

Covers project creation and Material Design Navigation Drawer

Post 2

Covers User Interface, adding/managing of Attendants and Events

Post 3

Covers adding business logic, functionalities and Data Persistence

Data Persistence

When users enter information about an event into our app, they expect that information to be there next time they open their app.  They expect your app to save their information. While the user is typing the information into your app, Android holds that information temporarily in the device memory, when the user is done with your app or if the user goes to use another app, it is your responsibility to save the information you collected. Android provides a few storage options for you to save your app data long term.

Two of the most common storage options in Android are SharedPreference and SQLite Database. The main difference between Android SharedPreference and SQLite is the size and the structure of the data that you want to save. If you want to save the list of things you want to do next summer you can save that list to the SharedPreference. It is both a small and unstructured data; however if you want to record the names of all your extended family and their contact information then you will do well to use a SQLite database because this will be a relatively bigger and structured data.

It will take a few blog post to cover SQLite in Android so I will publish a different tutorial series that will examine SQLite in detail. For this app we will use Object Relational Mapper or ORM for short. ORMs are tools that let developers work with a database using their familiar programming language. It is still expected that you understand the basic concept of databases which are columns and tables. What the ORM does is take your Java class like Attendant.java and map it or create for you a corresponding database called Attendant.

Sugar ORM 

List of Android ORM Retrieved from SlideShare

List f Android ORM

For this app we will use Sugar ORM to save our data. It is dead simple to use. There are other ORMs like the ones listed in the in side screen shot, also you can find comparison of Android ORMs in this post by Also Ziflag.

Add Sugar ORM – lets add Sugard ORM to our Attendance app in the following steps, the full walkthrough on how to setup Sugar ORM can be found here.

Step 1: Add Sugar ORM dependency to your gradle file like this

compile 'com.github.satyan:sugar:1.3'
 and then Specify SugarApp as your application class in manifest:  Here is the top of my Manifest  after adding SugarApp

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="okason.com.attendanceapp" >

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name="com.orm.SugarApp"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        tools:replace="android:icon">
        <meta-data
            android:name="DATABASE"
            android:value="attendance_app.db" />
        <meta-data
            android:name="VERSION"
            android:value="1" />
        <meta-data
            android:name="QUERY_LOG"
            android:value="true" />
        <meta-data
            android:name="DOMAIN_PACKAGE_NAME"
            android:value="okason.com.attendanceapp" />
        <activity
            android:name=".Activities.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

Step 2: Extend SugarRecord for all the classes that you need to save. Here is the updated list of our model classes after extending from Sugar ORM. Default constructor is required in all the classes.

Attendance. java class – this class holds an instance of every attendance, this way every check in and check out is associated with an attendant and an event.

public class Attendance extends SugarRecord<Attendance>{
    private Long CheckInTime;
    private Long CheckOutTime;
    private Event Event;
    private Attendant Attendant;

    //Default constructor
    public Attendance(){}
}

Event.java class to hold an instance of an event

public class Event extends SugarRecord<Event>{
    private String Name;
    private Long EventDate;
    private String Venue;
    private String City;
    private String SerializedAttendantsList;
    private String EventPicturePath; 

    //Default constructor needed for SugarORM
    public Event(){}
}

Attendant.java – this class holds an instance of an Attendant in our app.

public class Attendant extends SugarRecord<Attendant>{
    private String Name;
    private String Email;
    private String Phone;
    private String StreetAddress;
    private String City;
    private String State;
    private String PostalCode;
    private boolean IsCheckedIn;
    private String ProfileImagePath;
    private int ProfileImageId;
    private String SerializedAttendances;

    @Ignore
    private List<Attendance> Attendances;

    //Default constructor
    public Attendant(){}
}

Believe it or not, that is it with the database creation – or rather database setup. The database has not actually been created, the first time you save an object that is an instance of any these classes, Sugar ORM will create a database table with the same name as the classes. For example, here how to create and save an Attendant

Attendant guest1 = new Attendant();
        guest1.setName("Debbie Sam");
        guest1.setEmail("deb@email.net");
        guest1.setProfileImageId(R.drawable.headshot_1);
        guest1.save();

This will trigger the Sugar ORM initialization process which will take a peek at your class – a process known as reflection and then use the information it discovered to create  a database table named Attendant with columns corresponding to the properties in your class such as Name, Email, Street, etc – that is a great time saver versus creating it all by your self. Please make sure that you can save an object at this point before moving on.

Getters and Setters

Remember that for each of your class, you have to generate getters and setters. Right click on an empty space inside the class, click on Generate and select Getters and Setters, then highlight all your listed properties and click OK  

Implement Business Logic

Time to add some logic to our app. Our app has to do something other than a fancy UI. How do we know what logic to implement – we derive a list the list of functionalities to implement from the conversation we have with the project owner. Here is the list of functionalities we will implement for this app.

  1. Create Attendant
  2. Create Event
  3. Set an Event as Active
  4. Check In Attendant to a specific event
  5. Check Out Attendant from a specific event
  6. Share an event
  7. Delete an event

And we will implement the above functionalities with the following steps

Step 1: Create Attendant – We already have the UI that we can perform data entry with, and we have already enabled data persistence for our objects using Sugar ORM and now we need the logic that connects the UI to the database. To complete this functionality we need to update the AddAttendantFragment.java like this:

  1. In the AddAttendantFragment.java class, create class member variables to represent each field in the UI like this:
    private EditText mName, mEmail, mPhone, mStreet, mCity, mZip, mState;
  2. Using findViewById associate each variable above to their corresponding xml widget like this
    mName = (EditText) mRootView.findViewById(R.id.edit_text_client_name);
            mEmail = (EditText)mRootView.findViewById(R.id.edit_text_client_email);
            mPhone = (EditText) mRootView.findViewById(R.id.edit_text_client_phone);
            mPhone.setInputType(InputType.TYPE_CLASS_PHONE);
            mPhone.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
    
            mStreet = (EditText) mRootView.findViewById(R.id.edit_text_client_street_address);
            mCity = (EditText) mRootView.findViewById(R.id.edit_text_client_city);
            mState = (EditText) mRootView.findViewById(R.id.edit_text_client_state);
            mZip = (EditText) mRootView.findViewById(R.id.edit_text_client_zip_code);
  3. Attach an onClick listener to the button to listen for when the user touches the save button
    mSaveButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (requiredFieldsCompleted()){
                        saveAttendant();
                    }
                }
            });
  4. When the user touches the save button, check to see if the required fields are completed
    private boolean requiredFieldsCompleted() {
            //Check if required information are entered, here we are only checking for
            //Name and email and you can check for more or none
            boolean result = false;
            if (mName.getText() != null && !mName.getText().toString().isEmpty()) {
                result = true;
            } else {
                mName.setError(getString(R.string.required_fields_empty));
            }
    
            if (mEmail.getText() != null && !mEmail.getText().toString().isEmpty()) {
                result = true;
            } else {
                mEmail.setError(getString(R.string.required_fields_empty));
            }
            return result;
        }
  5. If the required fields are completed then create a new instance of an Attendant class that you defined in the models folder
    Attendant mAttendant = new Attendant();
  6. Use the text values of the class member variables to obtain the value that the user entered and use those to populate the Attendant object properties
  7. Save the Attendant object
    //Save to the database
    mAttendant.save();
  8. Notify the user that the Attendant has been saved
    //Provide feedback to the user
            Toast.makeText(getActivity(), mAttendant.getName() + " saved", Toast.LENGTH_SHORT).show();
  9. Clear the fields so the user can start over the process again
    private void resetFields(){
            //Wipe out any information the user entered so they can enter another
            //Attendant
            mName.setText("");
            mEmail.setText("");
            mPhone.setText("");
            mStreet.setText("");
            mCity.setText("");
            mState.setText("");
            mZip.setText("");
        }

And you can find the completed logic here.

Step 2: Create Event – We will follow the same process of adding a new attendant to add a new  event, we get programmatic reference to the widgets on the screen and then listen for when the user clicks the save button. When the save button is clicked we check to see that the fields we deem as important/required a completed and if they are we create a new object, populate that object with the data that was entered into the fields and save. Here is completed logic to add a new event. Note the  conversion that is required to get the date value that was entered.

Step 3: – Set Event as Active – for simplicity we will limit this app to check-in and check-out people from one event at a time. We accomplish this by setting the Id of any event to a SharedPreference, next time we want to set another event as the active event we simply override that id. The event has to be saved first in order for the event to have an id that we can save.

The method to set an event as the active ID will be set in the EventsListFragment.java, when the user touch an event we prompt to see if they want to set that event as the active and if yes, we use this method to save the event as the active event.

private void setEventAsActive(Event selectedEvent){
        //obtain an instance of the SharedPreference
        SharedPreferences mPref = getActivity().getSharedPreferences(Constants.PREFERENCE_FILE_KEY, Context.MODE_PRIVATE);
        SharedPreferences.Editor mEditor = mPref.edit();
        
        //put the id of the selected event to the SharedPreference
        mEditor.putLong(Constants.ACVTIVE_EVENT_ID, selectedEvent.getId());
        mEditor.commit();
        Toast.makeText(getActivity(), selectedEvent.getName() + " is now the Active Event", Toast.LENGTH_SHORT).show();
    }

Step 4: Check In Attendant to a specific event – we have now arrived at the core functionality of the app which is the ability to check in an attendant into an Event. There are many ways we can implement this functionality depending on the what this app is used for. Some examples are:

  1. Daycare check-in – this app could be used for a daycare check-in, in which case if a child gets checked in we need to add their name to the number of kids getting lunch so the cook will know the number of lunches to make
  2. Place of worship check-in – this app could be used to check-in worshipers to their place of worship as they arrive, the check-in functionality could just to update their record of attendance.
  3. Classroom check-in – this could be used to check-in students to class, and the teacher can provide numerous things that need to happen when the student check-in such as check if they are registered for the class, check lateness, etc
  4. What other use case can you see for this app, use the comment box to let me know, you never know we can explore it together.

For this demo, we are keeping the app generic so the check-in functionality is simply to toggle the Check-in button to Check-out and record the time of the Check-in. We will implement this in the AttendantAdapter.java that we created in part 2 of this tutorial series with following steps:

  1. In the onBindViewHolder method of the AttendantsAdapter.java class we setup a listener for when the check-in button is clicked
  2. When we detect a button click, we find out who is the attendant that want to check-in like this:
  3. Then we determine if this is a check-in or check-out click, if the Toggle button is “on” then it is a check-in if it is “off” then it is a check-out
  4. Then we create a new Attendance record and set the check-in time to be the current time
  5. We display a toast informing the user that he/she has been checked-in
  6. Here is the logic to implement the above steps
    public void onBindViewHolder(AttendantsAdapter.ViewHolder holder, int position) {
            final Attendant selectedAttendant = mAttendants.get(position);
            holder.checkInCheckOutButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //Is the toggle on?
                    boolean on = ((ToggleButton) v).isChecked();
    
                    if (on){
                        selectedAttendant.setIsCheckedIn(true);
    
                        //Create new attendance object
                        Attendance mAttendance = new Attendance();
    
                        //obtain an instance of SharedPreference
                        SharedPreferences mPref = mContext.getSharedPreferences(Constants.ATTENDANT_ID, Context.MODE_PRIVATE);
                        SharedPreferences.Editor mEditor = mPref.edit();
    
                        //get the id of the currently Active Event
                        long idOfTheActiveEvent = mPref.getLong(Constants.ACVTIVE_EVENT_ID, 0);
    
                        //Check if the active event is null
                        if (idOfTheActiveEvent > 0){
                            //Find the Active event from the database bawsed on the event ID
                            Event activeEvent = Event.findById(Event.class, idOfTheActiveEvent);
                            //Check if the event that you got back is null
                            if (activeEvent != null){
                                //associate this Attendance record to the selected active event
                                mAttendance.setEvent(activeEvent);
    
                                //associate this Attendance record to the selected Attendant
                                mAttendance.setAttendant(selectedAttendant);
    
                                //set the current time as the check-in time for this Attendance record
                                mAttendance.setCheckInTime(System.currentTimeMillis());
    
                                //notify user of successful check in
                                Toast.makeText(mContext, selectedAttendant.getName() + " checked in ", Toast.LENGTH_SHORT).show();
    
                            }else {
                                //The event is null, notify the user that there is no event to check
                                //into or to go to the Event list and set one of the listed events as active
                                Toast.makeText(mContext, "Unable to  checked in, no active event found ", Toast.LENGTH_SHORT).show();
                            }
                        }
    
                    } else {
                        selectedAttendant.setIsCheckedIn(false);
                        Toast.makeText(mContext, selectedAttendant.getName() + " checked out ", Toast.LENGTH_SHORT).show();
                    }
                }
            });
    
        }

Step 5: Check Out Attendant from a specific event – this step is the reverse of the check-in step and this is what will do to check-out an attendant:

  1. If we detect that the Toggle button click is for a check-out, we get all the attendance record in the database
  2. We loop through the record to see which one belongs to this user
  3. If we find the record that belongs to this user,
  4. We check if it has a check in time and no checkout time
  5. If we find a check-in and no check-out then we check-out the user
  6. Here is the logic to check out an Attendant
    else {
                        //If this is a checkout
                        List<Attendance> AllTheAttendanceRecords = Attendance.listAll(Attendance.class);
                        
                        //Ensure the Attendance record is not empty
                        if (AllTheAttendanceRecords != null && AllTheAttendanceRecords.size() > 0) {
                            //Go through all the attendance record to find out which record belongs to this attendant
                            for (Attendance record: AllTheAttendanceRecords){
                                if (record.getAttendant().equals(selectedAttendant)){
                                    //This attendance record belongs to the selected Attendanc
                                    //Check if check-out time is empty
                                    if (record.getCheckInTime() != null && record.getCheckOutTime() == null){
                                        //set the check-out time
                                        record.setCheckOutTime(System.currentTimeMillis());
                                        Toast.makeText(mContext, selectedAttendant.getName() + " checked out ", Toast.LENGTH_SHORT).show();                                    
                                    }
                                    //no need to continue checking
                                    break;
                                }
                                Toast.makeText(mContext, " Unable to check out - no attendance record found ", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }

Step 6: Share an Event – why not the organizer will like to share an event and implementing the Share intent is one of the frequent actions you will perform in the apps that you will build. Here is the method to share an Event and this needs to be implemented in the EventsListFragment.java

private void shareEvent(Event selectedEvent){
        java.text.DateFormat dateFormat = DateFormat.getMediumDateFormat(getActivity());

        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        shareIntent.putExtra(Intent.EXTRA_TEXT, "You are invited to our upcoming event - " +
                selectedEvent.getName() + " on " + dateFormat.format(selectedEvent.getEventDate()));
        shareIntent.setType("text/plain");
        startActivity(shareIntent);
    }

Step 7: Delete an Event – oops, the organizer changed their mind and want now to deleted an event. In the EventsListFragment.java where all the events are listed, we implement this method to delete an event like this:

private void deleteEvent(Event selectedEvent){
        AlertDialog.Builder saveDialog = new AlertDialog.Builder(getActivity());
        saveDialog.setTitle("Delete Event!");
        saveDialog.setMessage("Are you sure you want to delete " + selectedEvent.getName() + "?");
        saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
               selectedEvent.delete();
            }
        });
        saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });
        saveDialog.show();
    }

Summary

We touched on quite a few concepts here that it will take much longer post to try to explain them one by one. If you have questions use the comments box to ask.  I will create a separate post for App publishing

If you like this tutorial please share it with someone who can benefit from it or through your social media, If you want to be notified when I release the next tutorial in the series please use the opt-in form below to join my mailing list. If you need clarifications, use the comment button below to ask questions. If you have feedback for me on how I can improve my tutorials or what topic you want to learn more about, use the contact form to reach out to me.

<form action='//valokafor.us4.list-manage.com/subscribe/post?u=0600ce94a59d7720819aa3dd8&id=6e5492cf7d' class='frm' method='post'><input type='text' placeholder='Email Address' name='EMAIL' /><input type='text' placeholder='First Name' name='FNAME' /><input type='hidden' name='b_0600ce94a59d7720819aa3dd8_6e5492cf7d' value='' />
<input type='submit' value="Send Me New Tutorials">
</form>

Follow Me

<script>jQuery(window).load(function() { ThriveApp.load_script('twitter'); });</script>
<script>jQuery(window).load(function() { ThriveApp.load_script('google'); });</script>
<script type='IN/MemberProfile' data-format='inline' data-id='https://www.linkedin.com/in/valokafor'></script>
<script>jQuery(window).load(function() { ThriveApp.load_script('linkedin'); });</script>

Source Code

You can find the Source Code for this Tutorial @ Github

The post Create Your First Android App – Part 3 appeared first on Val Okafor.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) ValOkafor.com
United States United States
My name is Val Okafor, I am a Senior Software Engineer with specialization in Android Development. Learning and problem solving is my passion and I share my Android development knowledge through my blog ValOkafor.com.

My Android courses are the courses I wish I had when I started. I teach Android development in the context of a fully developed Android app. I believe that new Android concepts are better understood if they are presented in the context of creating an app from scratch to finish.

I focus on creating Productivity Android apps and besides Android development I have 7 years’ experience as System Administrator supporting Enterprise applications and 2 years’ experience as a Web Developer building websites using PHP and ASP.Net.

I have worked for corporations such as The Home Depot, American Council on Exercise, Legend3D and HD Supply, Inc. I have a bachelor's degree in Information Technology from National University San Diego, California and a master's degree in Software Engineering from Regis University Denver, Colorado.

I enjoy sharing my extensive work experience through my blog, social media.

Comments and Discussions

 
QuestionAndroid Studio Pin
tonye siegha6-Aug-15 21:57
tonye siegha6-Aug-15 21:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.