ToDo App In Android with FireBase Database


This tutorial will give you basic idea what Firebase is, and we are going to develop a simple app in Android. The application will be able to add new task, and remove it in real-time from database.


CREATE AN ANDROID STUDIO PROJECT

Objectives

In this tutorial , you will learn how to : 
  • Create a simple Android app using Android Studio. 
  • Connect your app to Firebase to store data.
  • Populate RecyclerView and Add data to RecyclerView
  • Add and delete data from Recyclerview which is connected to database 
  • Create a backend service running on App Engine using Android Studio.

Prerequisites

  • You should have Android studio installed, and have basic understanding of how it works.
  • Sign in your google account to have your firebease database on cloud.

 Create an Android Project in Android Studio. 


You can give your app desired name , and for sake of this tutorial, i am giving package name as com.apprajapati.todoapp. Now click next to select a API LEVEL. 


After selecting your API level, click next and add new Blank Activity.


After selecting blank, it will show you details of your xml and classes files, leave them as default and press finish to complete your project. Now we have our project ready, lets talk about our back-end Firebase.


INTRODUCTION TO FIREBASE



The firebase is real-time database for your Application. Your data will be stored in JSON form and synchronized in realtime upon the request of connection from client. Its all in one feature enable you to have single database for all the platform such as Web application, Android application and iOS application.

Firebase offers all the database and functionality such as data storage, synchronization , user authentication and more. You can enable user authentication of facebook, google+, etc every easily.

I will suggest you to read more about it on : https://www.firebase.com/docs/android/  for Android platform. You can also get information about other platforms if you wish to.


SETUP FIREBASE DATABASE 


Sign in to your Google account, and go to https://www.firebase.com . You will be able to login using your google account or you can use alternative email.

After completing the registration , go to the console dashboard and click on create new project, and give your appName and Location and click on create project.

Click on create project to continue, and you will be shown the following platforms to choose. Choose the ANDROID platform to continue. 


In the next Window, you will be asked for package name of your application. In this tutorial, i have given my app package name as com.apprajapati.todoapp . You can give your desired name and press ADD APP to continue. 

When you will press continue, you will be shown following step with unique file for your app.
 



This file is unique to your project. Save the downloaded file, we will need that file later, and press continue. Now, it will show you necessary dependencies you need to add in your project. 



Now that you have everything set up, to configure your database, go to database on your console and click on rules as shown in the image below. 

Delete the rules and replace the rules with following code. I recommend you typing this rule into your dashboard. Copy and paste will mostly likely gives an error.
 { “rules”: 
{ “.read”: true,
“.write”: true
}
}

This rule defines our database as public. For this tutorial, i am using public database, but you can personalize it by yourself and i leave that up to you. For now, lets just create a basic app that would add task and remove task from database and shows the data on our app. I recommend you looking more into database rules.


ANDROID APP CLIENT


Let me show you guys how our app would look like. It is basic app, where you can add your ToDo task. The task you will add in your app, it will be stored in our Firebase database and retrieved when you open the app.



I assume that by now, you have added the dependencies that are necessary for Firebase database and have added the google-services.json file shown in the Firebase database setup guide.

In this app, we are going to use the Internet, and the app won't be able to fetch the data if we don't give permission to our app. So in order to do that, add the following permission in your AndroidManifest.xml file.
    <uses-permission android:name="android.permission.INTERNET"/> 


Your android project will have MainActivity.java and its two layout files namely activity_main.xml and content_main.xml. This files are default created with blank activity project.

Now you can create following app structure as shown in the image below.



To add the RecyclerView and Widgets necessary to add task , lets add following code inside your content_main.xml file, this file will be shown on screen as MainActivity.

 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:paddingTop="@dimen/actionbar_"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/task_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/add_task_wrapper"
android:layout_marginBottom="12dp"
android:orientation="vertical"
android:scrollbars="none"/>
<LinearLayout
android:id="@+id/add_task_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<EditText
android:id="@+id/add_task_box"
android:layout_width="0dp"
android:inputType="text"
android:layout_height="match_parent"

android:layout_weight="7"/>
<Button
android:id="@+id/add_task_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="@string/add_task_button"
android:padding="12dp"
android:layout_margin="0dp"
android:layout_weight="3"/>
</LinearLayout>

</RelativeLayout>

The above code will generate our MainActivity screen as the image shown below.


Now, Add following code inside your MainActivity.java

 
public class MainActivity extends AppCompatActivity {


    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLinearLayoutManager;
    private RecyclerViewAdapter mRecyclerAdapter;
    private EditText mTaskEditText;
    private DatabaseReference databaseReference;

    private List listOfTask;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);


        //Array list of all tasks
        listOfTask = new ArrayList<>();
        //get the database reference of FIREBASE
        databaseReference = FirebaseDatabase.getInstance().getReference();
        //this is where you can enter text of your task
        mTaskEditText = (EditText) findViewById(R.id.add_task_box);
        
        //Initializing RecyclerView
        mRecyclerView = (RecyclerView) findViewById(R.id.task_list);
        //As we are showing data in Linear form we are using this
        mLinearLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLinearLayoutManager);

        //When we add text of task, and press Button "Add task" triggers this
        Button addTaskButton = (Button) findViewById(R.id.add_task_button);

        assert addTaskButton != null;
        addTaskButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String enteredTask = mTaskEditText.getText().toString();
                if(TextUtils.isEmpty(enteredTask)){
                    Toast.makeText(MainActivity.this, "You must enter a task to Add it",Toast.LENGTH_LONG).show();
                    return;
                }
                else{
                    //If task text is valid Add it in our FIREBASE DATABASE.
                    Task taskObject = new Task(enteredTask);
                    
                    databaseReference.push().setValue(taskObject);
                    mTaskEditText.setText("");
                }

            }
        });

        //Database helper methods
        databaseReference.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                //if added , show all 
                getAllTask(dataSnapshot);
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
               //if changed show all 
                getAllTask(dataSnapshot);
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                //delete the task 
                taskDeletion(dataSnapshot);
            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });

    }
    
    //On delete, remove the task from Firebase database - REAL TIME
    private void taskDeletion(DataSnapshot dataSnapshot) {

        for (DataSnapshot singleDataSnapshot : dataSnapshot.getChildren()) {

            String currentTask = singleDataSnapshot.getValue(String.class);
            for (int i = 0; i < listOfTask.size(); i++) {
                if (listOfTask.get(i).getTask().equals(currentTask)) {
                    listOfTask.remove(i);
                }


            }

            //After removing , send notification to RecyclerView to remove the element 
            // AND re adapt it
            mRecyclerAdapter.notifyDataSetChanged();
            mRecyclerAdapter = new RecyclerViewAdapter(MainActivity.this, listOfTask);
            mRecyclerView.setAdapter(mRecyclerAdapter);

        }
    }

    private void getAllTask(DataSnapshot dataSnapshot) {

        //get all task when opening the app.
        for(DataSnapshot singleShot : dataSnapshot.getChildren()){
            String taskTitle = singleShot.getValue(String.class);
            listOfTask.add(new Task(taskTitle));
            mRecyclerAdapter = new RecyclerViewAdapter(MainActivity.this,listOfTask);
            mRecyclerView.setAdapter(mRecyclerAdapter);
        }

    }

}




Now that we have added MainActivity, we are referencing here to RecyclerView. Now, RecyclerView must have its own view holder and Adapter to represent the data.

Lets add following two files code.

RecyclerViewAdapter.java


 
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolders> {

private List<Task> tasks;
protected Context context;

public RecyclerViewAdapter(Context context, List<Task> allTask){
this.tasks = allTask;
this.context = context;
}

@Override
public RecyclerViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerViewHolders viewHolders = null;
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.to_do_list, parent,false);
viewHolders = new RecyclerViewHolders(view,tasks);
return viewHolders;
}

@Override
public void onBindViewHolder(RecyclerViewHolders holder, int position) {
holder.categoryTitle.setText(tasks.get(position).getTask());

}

@Override
public int getItemCount() {
return this.tasks.size();
}


}
If you notice carefully, we need layout file for our RecyclerView. It is named as to_do_list.xml . This file will define how our Recyclerview will adapt the data and how will it look like. So, add the following code inside to_do_list.xml.


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="18dp"
android:paddingBottom="18dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/task_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/check"
android:layout_weight="15"
android:contentDescription="@string/app_name" />

<TextView
android:id="@+id/task_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="70"
android:text="@string/app_name"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp"
/>

<ImageView
android:id="@+id/task_delete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/delete_forever"
android:layout_weight="15"
android:contentDescription="@string/app_name" />

</LinearLayout>

This file will look as follows in Android studio. As you can see, it represents how our icon and text will set up in LinearLayout of RecyclerView. Adapter is always used to adapt the data inside views such as RecyclerView or ListView.



Now lets add RecyclerViewHolders.java .


public class RecyclerViewHolders extends RecyclerView.ViewHolder {

private static final String TAG = RecyclerViewHolders.class.getSimpleName();
public ImageView markIcon;
public TextView categoryTitle;
public ImageView deleteIcon;
private List taskObject;

public RecyclerViewHolders(View itemView, final List taskObject) {
super(itemView);

this.taskObject = taskObject;
categoryTitle = (TextView) itemView.findViewById(R.id.task_title);
markIcon = (ImageView) itemView.findViewById(R.id.task_icon);
deleteIcon = (ImageView) itemView.findViewById(R.id.task_delete);
deleteIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {


String taskTitle = taskObject.get(getAdapterPosition()).getTask();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query deletequery = reference.orderByChild("task").equalTo(taskTitle);
deletequery.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot appleSnapshot: dataSnapshot.getChildren()) {
appleSnapshot.getRef().removeValue();

}
}

@Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "Cancelled Exception", databaseError.toException());
}
});
}
});
}
}

If you have noticed, we are passing the Object of array. We need Task.java class that can represent a particular object which we can have array of task object.

Add new class file naming it Task.java, and add following code.


public class Task {

private String task;
public Task() {}
public Task(String task) {
this.task = task;
}
public String getTask() {
return task;
}
}

After this, you are ready to run the App. You can monitor your database. As you add the task in your app, it will be shown in your firebase database as well.

Here's the task i had added in our first screenshot of our app.



As you can see, we can show our data has been added to our database as well. This is how Firebase makes our life easy by providing real time synchronized database.

Will upload the working code files soon. In the meantime, if you guys have any comment, or suggestion please lave a comment.

Happy Coding guys!



References :
1. https://firebase.google.com/docs/database/ -Documentation and features
2. https://cloud.google.com/solutions/mobile/firebase-app-engine-android-studio - Tutorial

Post a Comment

1 Comments