A ToDo Task app is where we can save schedules of some tasks to get reminded on the scheduled time. The tasks we save in the app can be saved multiple ways, online or offline. Some app supports both. In this tutorial we are going to create a SQLite Database based ToDo Task App using Java in Android.

The above video demonstrate the app we’ll be building today in Android Studio using Java to save our daily tasks. You can directly download the full Android Studio Project below, but I would suggest to read the article first for your better understanding.

Download ToDo Task App Source Code

Download the Android Studio source code of ToDo Task App using Java in Android
Size: 160.88 Kb

You can also find the project in GitHub.

Short Notes on Android SQLite Database

Android SQLite is a very lightweight database which comes with Android OS. Android SQLite combines a clean SQL interface with a very small memory footprint and decent speed. For Android, SQLite is “baked into” the Android runtime, so every Android application can create its own SQLite databases.

Android SQLite native API is not JDBC, as JDBC might be too much overhead for a memory-limited smartphone. Once a database is created successfully its located in data/data//databases/ accessible from Android Device Monitor.

SQLite is a typical relational database, containing tables (which consists of rows and columns), indexes etc. We can create our own tables to hold the data accordingly. This structure is referred to as a schema.

I have already written a tutorial on basics of SQLite Database using Kotlin which might help you also.

Create necessary Drawable Resource Files

When there will be no task in the app we’ll display a stylish rounded border button to open an activity to add new task. The button will look like

As you can see that the button looks different from the android default button, I created some drawable resource files to change the default design.

radius_border_button.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true" >
        <shape android:shape="rectangle"  >
            <corners android:radius="90dip" />
            <stroke android:width="1dip" android:color="#444444" />
            <solid android:color="#FFFFFF"/>
        </shape>
    </item>
    <item >
        <shape android:shape="rectangle"  >
            <corners android:radius="90dip" />
            <stroke android:width="1dip" android:color="#EC5D5D" />
            <solid android:color="#FFFFFF"/>
        </shape>
    </item>
</selector>

radius_border_button_text.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Focused and pressed -->
    <item android:state_pressed="true"
        android:color="#444444" />

    <!-- Default color -->
    <item android:color="#EC5D5D" />

</selector>

These will help us to customize the button letter. You can modify them to change the Button design and text colors in both normal and pressed state.

Create a database using SQLiteOpenHelper

For storing the tasks in our device, we’ll create a class that will contain all database related functionality like creating the database for first time, inserting new data, updating existing data or deleting specific data. But before that let me show you how are database table will look like.

idtasktask_atstatus
1Task Details 1dd/MM/yyyy1
2Task Details 2dd/MM/yyyy0
Table Name: todo

So I guess, you understood how our data will be saved in a Table. We’ll create our database, then create our table “todo” with these 4 attributes or columns:

  • id – It will contain integer values and it will increment automatically.
  • task – It will contain task details.
  • task_at – It will contain the performing date of the task.
  • status – It will be used to identify whether the task is completed or not. 0 will be for incomplete and 1 will be for completed.

So create a new Java file named “DBHelper.java” and place the below codes.

package com.frsarker.todotask;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.Date;


public class DBHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "ToDoDBHelper.db";
    public static final String TABLE_NAME = "todo";

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub

        db.execSQL(
                "CREATE TABLE " + TABLE_NAME + "(id INTEGER PRIMARY KEY, task TEXT, task_at DATETIME, status INTEGER)"
        );
    }


    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }


    public boolean insertTask(String task, String task_at) {
        Date date;
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put("task", task);
        contentValues.put("task_at", task_at);
        //contentValues.put("dateStr", getDate(dateStr));
        contentValues.put("status", 0);
        db.insert(TABLE_NAME, null, contentValues);
        return true;
    }

    public boolean updateTask(String id, String task, String task_at) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();

        contentValues.put("task", task);
        contentValues.put("task_at", task_at);

        db.update(TABLE_NAME, contentValues, "id = ? ", new String[]{id});
        return true;
    }

    public boolean deleteTask(String id) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(TABLE_NAME, "id = ? ", new String[]{id});
        return true;
    }

    public boolean updateTaskStatus(String id, Integer status) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();

        contentValues.put("status", status);

        db.update(TABLE_NAME, contentValues, "id = ? ", new String[]{id});
        return true;
    }


    public Cursor getSingleTask(String id) {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor res = db.rawQuery("select * from " + TABLE_NAME + " WHERE id = '" + id + "' order by id desc", null);
        return res;

    }

    public Cursor getTodayTask() {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor res = db.rawQuery("select * from " + TABLE_NAME + " WHERE date(task_at) = date('now', 'localtime') order by id desc", null);
        return res;

    }


    public Cursor getTomorrowTask() {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor res = db.rawQuery("select * from " + TABLE_NAME + " WHERE date(task_at) = date('now', '+1 day', 'localtime')  order by id desc", null);
        return res;

    }


    public Cursor getUpcomingTask() {
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor res = db.rawQuery("select * from " + TABLE_NAME + " WHERE date(task_at) > date('now', '+1 day', 'localtime') order by id desc", null);
        return res;

    }


}

The insertTask(), updateTask(), deleteTask(), updateTaskStatus() will be used for adding new task, modifying existing task, deleting a task and changing the status for completed or incompleted task respectively.

Remove Default ActionBar

As you know that by default there will be a ActionBar in each activity. We will remove it to customize our own ActionBar desihn using Android ToolBar. But before that, our task is to remove the default one. You will find styles.xml under values. Replace everything with the below code.

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="CustomTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#FFFFFF</color>
    <color name="colorPrimaryDark">#FFFFFF</color>
    <color name="colorAccent">#EC5D5D</color>
</resources>

Check that our style theme name is “CustomTheme” this should be in you AndroidManifest also so that in each activity the default ActionBar is removed.

<?xml version="1.0" encoding="utf-8"?>
<manifest
	....
	... >
    <application
        ...
	...
        android:theme="@style/CustomTheme">
        ...
	...
    </application>
</manifest>

Later I will provide the full codes of my AndroidManifest.xml

Add Necessary Dependency

For using different Google’s Material Views in our layout i.e. FloatingActionButton we’ll have to add the below dependency in our app level build.gradle file

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
	...
    ...
	...

    implementation 'com.google.android.material:material:1.0.0'
}

The time I’m writing this article, version 1.0.0 is the stable version of this library. You should use the latest library always. You can find the latest library version from MVN Repository.

Create Custom ListView – Scrolling Disabled

We will create a custom listview which will have no scrolling functionality as we will need to use multiple listview in our single activity. Create a New Java File and name it NoScrollListView.java and put the codes below.

NoScrollListView.java

package com.frsarker.todotask;

import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ListView;

// creates a list view with scrolling disabled
public class NoScrollListView extends ListView {

    public NoScrollListView(Context context) {
        super(context);
    }
    public NoScrollListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public NoScrollListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
        ViewGroup.LayoutParams params = getLayoutParams();
        params.height = getMeasuredHeight();
    }
}

Remember on thing, when we will implement this view in our activity layout, change the package name according to yours.

Add / Modify / Delete Task Activity

These features are important to be implemented in a ToDo Task app. In our tutorial we’ll do all of these things into One Activity. If it’s an existing task then it will act like Modify Task and Delete Task, otherwise it will act like Add New Task. No I’ll not describe codes briefly, cause here we will just call different functions written in our DBHelper.java class.

activity_add_modify_task.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:elevation="0dp">

        
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:contentInsetStart="0dp">
            <LinearLayout
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/toolbar_title"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="center"
                    android:text="New Task"
                    android:textColor="#EC5D5D"
                    android:textSize="18dp"
                    android:textStyle="bold"/>


            </LinearLayout>
        </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.AppBarLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <EditText
            android:id="@+id/edit_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/custom_config"
            android:background="#FFFFFF"
            android:gravity="top"
            android:inputType="textMultiLine"
            android:padding="20dp"
            android:textColorHint="#CDD1D5"
            android:hint="What are you planning?"/>



        <LinearLayout
            android:id="@+id/custom_config"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/deleteTask"
            android:gravity="center"
            android:orientation="horizontal"
            android:paddingHorizontal="30dp"
            android:paddingVertical="20dp"
            android:onClick="chooseDate">

            <ImageView
                android:layout_width="16dp"
                android:layout_height="16dp"
                android:src="@drawable/cal"/>

            <TextView
                android:id="@+id/dateText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:textSize="16dp"
                android:textStyle="bold"
                android:text="29/05/2020"/>

        </LinearLayout>

        <LinearLayout
            android:id="@+id/deleteTask"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/save_btn"
            android:gravity="center"
            android:orientation="horizontal"
            android:paddingHorizontal="30dp"
            android:paddingVertical="20dp"
            android:onClick="deleteTask"
            android:visibility="gone">

            <ImageView
                android:layout_width="16dp"
                android:layout_height="16dp"
                android:src="@drawable/del"
                android:tint="#EC5D5D"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:textSize="16dp"
                android:textStyle="bold"
                android:textColor="#EC5D5D"
                android:text="Delete Task"/>

        </LinearLayout>


        <Button
            android:id="@+id/save_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_gravity="center"
            style="?android:attr/borderlessButtonStyle"
            android:background="#EC5D5D"
            android:textColor="#FFFFFF"
            android:paddingVertical="15dp"
            android:onClick="saveTask"
            android:text="SAVE"/>

    </RelativeLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>

date_picker.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">

    <DatePicker
        android:id="@+id/date_picker"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:calendarViewShown="false"
        android:datePickerMode="spinner"/>

</LinearLayout>

AddModifyTask.java

package com.frsarker.todotask;

import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class AddModifyTask extends AppCompatActivity {

    Calendar calendar;
    DBHelper mydb;

    Boolean isModify = false;
    String task_id;
    TextView toolbar_title;
    EditText edit_text;
    TextView dateText;
    Button save_btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        setContentView(R.layout.activity_add_modify_task);

        mydb = new DBHelper(getApplicationContext());
        calendar = new GregorianCalendar();
        toolbar_title = findViewById(R.id.toolbar_title);
        edit_text = findViewById(R.id.edit_text);
        dateText = findViewById(R.id.dateText);
        save_btn = findViewById(R.id.save_btn);


        dateText.setText(new SimpleDateFormat("E, dd MMMM yyyy").format(calendar.getTime()));


        Intent intent = getIntent();
        if (intent.hasExtra("isModify")) {
            isModify = intent.getBooleanExtra("isModify", false);
            task_id = intent.getStringExtra("id");
            init_modify();
        }


    }

    public void init_modify() {
        toolbar_title.setText("Modify Task");
        save_btn.setText("Update");
        LinearLayout deleteTask = findViewById(R.id.deleteTask);
        deleteTask.setVisibility(View.VISIBLE);
        Cursor task = mydb.getSingleTask(task_id);
        if (task != null) {
            task.moveToFirst();


            edit_text.setText(task.getString(1));

            SimpleDateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd");
            try {
                calendar.setTime(iso8601Format.parse(task.getString(2)));
            } catch (ParseException e) {
            }

            dateText.setText(new SimpleDateFormat("E, dd MMMM yyyy").format(calendar.getTime()));


        }

    }


    public void saveTask(View v) {

        /*Checking for Empty Task*/
        if (edit_text.getText().toString().trim().length() > 0) {

            if (isModify) {
                mydb.updateTask(task_id, edit_text.getText().toString(), new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
                Toast.makeText(getApplicationContext(), "Task Updated.", Toast.LENGTH_SHORT).show();
            } else {
                mydb.insertTask(edit_text.getText().toString(), new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()));
                Toast.makeText(getApplicationContext(), "Task Added.", Toast.LENGTH_SHORT).show();
            }
            finish();

        } else {
            Toast.makeText(getApplicationContext(), "Empty task can't be saved.", Toast.LENGTH_SHORT).show();
        }

    }

    public void deleteTask(View v) {
        mydb.deleteTask(task_id);
        Toast.makeText(getApplicationContext(), "Task Removed", Toast.LENGTH_SHORT).show();
        finish();
    }


    public void chooseDate(View view) {
        final View dialogView = View.inflate(this, R.layout.date_picker, null);
        final DatePicker datePicker = dialogView.findViewById(R.id.date_picker);
        datePicker.updateDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));


        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setView(dialogView);
        builder.setTitle("Choose Date");
        builder.setNegativeButton("Cancel", null);
        builder.setPositiveButton("Set", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {


                calendar = new GregorianCalendar(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
                dateText.setText(new SimpleDateFormat("E, dd MMMM yyyy").format(calendar.getTime()));

            }
        });
        builder.show();
    }
}

If you want to learn more on Formatting Date & Time using Java in Android, I have written an article already which might help you.

Display Tasks of Today / Tomorrow / Upcoming

This is our last step also the Activity that will be launched first. Here we will display our task automatically under Today, Tomorrow and Upcoming Tasks category. Also user will be able to check whether the task is completed or not. As the activity will display tasks in ListView, we will also create custom ListView Adapter.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF">


    <androidx.core.widget.NestedScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:clipToPadding="false"
        android:isScrollContainer="false"
        android:visibility="gone"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">


            <LinearLayout
                android:id="@+id/todayContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginHorizontal="30dp"
                    android:layout_marginTop="60dp"
                    android:layout_marginBottom="10dp"
                    android:text="Today's Tasks"
                    android:textColor="#111111"
                    android:textSize="27sp"
                    android:textStyle="bold" />

                <com.frsarker.todotask.NoScrollListView
                    android:id="@+id/taskListToday"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:divider="#30CCCCCC"
                    android:dividerHeight="1dp" />

            </LinearLayout>


            <LinearLayout
                android:id="@+id/tomorrowContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">


                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginHorizontal="30dp"
                    android:layout_marginTop="60dp"
                    android:layout_marginBottom="10dp"
                    android:text="Tomorrow's Tasks"
                    android:textColor="#111111"
                    android:textSize="27sp"
                    android:textStyle="bold" />

                <com.frsarker.todotask.NoScrollListView
                    android:id="@+id/taskListTomorrow"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:divider="#30CCCCCC"
                    android:dividerHeight="1dp" />

            </LinearLayout>


            <LinearLayout
                android:id="@+id/otherContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">


                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginHorizontal="30dp"
                    android:layout_marginTop="60dp"
                    android:layout_marginBottom="10dp"
                    android:text="Upcoming Tasks"
                    android:textColor="#111111"
                    android:textSize="27sp"
                    android:textStyle="bold" />

                <com.frsarker.todotask.NoScrollListView
                    android:id="@+id/taskListUpcoming"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:divider="#30CCCCCC"
                    android:dividerHeight="1dp" />

            </LinearLayout>


        </LinearLayout>

    </androidx.core.widget.NestedScrollView>


    <LinearLayout
        android:id="@+id/empty"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:padding="30dp"
        android:visibility="visible">

        <TextView
            android:id="@+id/emptyTxt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hey"
            android:textColor="#EC5D5D"
            android:textSize="38dp"
            android:textStyle="normal" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="you are\nfree today"
            android:textColor="#323872"
            android:textSize="34dp"
            android:textStyle="bold" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:text="You have no task to do today"
            android:textColor="#CDD1D5"
            android:textSize="22dp"
            android:textStyle="bold" />

        <Button
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="50dp"
            android:background="@drawable/radius_border_button"
            android:onClick="openAddModifyTask"
            android:paddingHorizontal="70dp"
            android:paddingVertical="15dp"
            android:text="Add New Task"
            android:textColor="@drawable/radius_border_button_text" />

    </LinearLayout>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="16dp"
        android:contentDescription="Add Task"
        android:onClick="openAddModifyTask"
        android:src="@drawable/ic_fab_add" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

task_list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:weightSum="1"
        android:orientation="horizontal"
        android:paddingHorizontal="30dp"
        android:paddingVertical="15dp">


        <CheckBox
            android:id="@+id/checkBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

        <Space
            android:layout_width="15dp"
            android:layout_height="match_parent"/>

        <TextView
            android:id="@+id/task_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textColor="#222222"
            android:text="Task Name"
            android:textStyle="normal"
            android:textSize="19sp"/>


    </LinearLayout>
</LinearLayout>

ListTaskAdapter.java

package com.frsarker.todotask;

import android.app.Activity;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.HashMap;


public class ListTaskAdapter extends BaseAdapter {
    private Activity activity;
    private ArrayList<HashMap<String, String>> data;
    private DBHelper database;

    public ListTaskAdapter(Activity a, ArrayList<HashMap<String, String>> d, DBHelper mydb) {
        activity = a;
        data = d;
        database = mydb;
    }

    public int getCount() {
        return data.size();
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ListTaskViewHolder holder = null;
        if (convertView == null) {
            holder = new ListTaskViewHolder();
            convertView = LayoutInflater.from(activity).inflate(R.layout.task_list_row, parent, false);
            holder.task_name = convertView.findViewById(R.id.task_name);
            holder.checkBtn = convertView.findViewById(R.id.checkBtn);
            convertView.setTag(holder);
        } else {
            holder = (ListTaskViewHolder) convertView.getTag();
        }


        final HashMap<String, String> singleTask = data.get(position);
        final ListTaskViewHolder tmpHolder = holder;

        holder.task_name.setId(position);
        holder.checkBtn.setId(position);

        try {


            holder.checkBtn.setOnCheckedChangeListener(null);
            if (singleTask.get("status").contentEquals("1")) {
                holder.task_name.setText(Html.fromHtml("<strike>" + singleTask.get("task") + "</strike>"));
                holder.checkBtn.setChecked(true);
            } else {
                holder.task_name.setText(singleTask.get("task"));
                holder.checkBtn.setChecked(false);
            }

            holder.checkBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (isChecked) {
                        database.updateTaskStatus(singleTask.get("id"), 1);
                        tmpHolder.task_name.setText(Html.fromHtml("<strike>" + singleTask.get("task") + "</strike>"));
                    } else {
                        database.updateTaskStatus(singleTask.get("id"), 0);
                        tmpHolder.task_name.setText(singleTask.get("task"));
                    }

                }
            });


        } catch (Exception e) {
        }
        return convertView;
    }
}

class ListTaskViewHolder {
    TextView task_name;
    CheckBox checkBtn;
}

MainActivity.java

package com.frsarker.todotask;

import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.widget.NestedScrollView;

import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity {

    DBHelper mydb;
    LinearLayout empty;
    NestedScrollView scrollView;
    LinearLayout todayContainer, tomorrowContainer, otherContainer;
    NoScrollListView taskListToday, taskListTomorrow, taskListUpcoming;
    ArrayList<HashMap<String, String>> todayList = new ArrayList<HashMap<String, String>>();
    ArrayList<HashMap<String, String>> tomorrowList = new ArrayList<HashMap<String, String>>();
    ArrayList<HashMap<String, String>> upcomingList = new ArrayList<HashMap<String, String>>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        setContentView(R.layout.activity_main);

        mydb = new DBHelper(this);
        empty = findViewById(R.id.empty);
        scrollView = findViewById(R.id.scrollView);
        todayContainer = findViewById(R.id.todayContainer);
        tomorrowContainer = findViewById(R.id.tomorrowContainer);
        otherContainer = findViewById(R.id.otherContainer);
        taskListToday = findViewById(R.id.taskListToday);
        taskListTomorrow = findViewById(R.id.taskListTomorrow);
        taskListUpcoming = findViewById(R.id.taskListUpcoming);
    }

    public void openAddModifyTask(View view) {
        startActivity(new Intent(this, AddModifyTask.class));
    }


    @Override
    public void onResume() {
        super.onResume();
        populateData();
    }


    public void populateData() {
        mydb = new DBHelper(this);

        runOnUiThread(new Runnable() {
            public void run() {
                fetchDataFromDB();
            }
        });
    }


    public void fetchDataFromDB() {
        todayList.clear();
        tomorrowList.clear();
        upcomingList.clear();

        Cursor today = mydb.getTodayTask();
        Cursor tomorrow = mydb.getTomorrowTask();
        Cursor upcoming = mydb.getUpcomingTask();

        loadDataList(today, todayList);
        loadDataList(tomorrow, tomorrowList);
        loadDataList(upcoming, upcomingList);


        if (todayList.isEmpty() && tomorrowList.isEmpty() && upcomingList.isEmpty()) {
            empty.setVisibility(View.VISIBLE);
            scrollView.setVisibility(View.GONE);
        } else {
            empty.setVisibility(View.GONE);
            scrollView.setVisibility(View.VISIBLE);

            if (todayList.isEmpty()) {
                todayContainer.setVisibility(View.GONE);
            } else {
                todayContainer.setVisibility(View.VISIBLE);
                loadListView(taskListToday, todayList);
            }

            if (tomorrowList.isEmpty()) {
                tomorrowContainer.setVisibility(View.GONE);
            } else {
                tomorrowContainer.setVisibility(View.VISIBLE);
                loadListView(taskListTomorrow, tomorrowList);
            }

            if (upcomingList.isEmpty()) {
                otherContainer.setVisibility(View.GONE);
            } else {
                otherContainer.setVisibility(View.VISIBLE);
                loadListView(taskListUpcoming, upcomingList);
            }
        }
    }


    public void loadDataList(Cursor cursor, ArrayList<HashMap<String, String>> dataList) {
        if (cursor != null) {
            cursor.moveToFirst();
            while (cursor.isAfterLast() == false) {

                HashMap<String, String> mapToday = new HashMap<String, String>();
                mapToday.put("id", cursor.getString(0).toString());
                mapToday.put("task", cursor.getString(1).toString());
                mapToday.put("date", cursor.getString(2).toString());
                mapToday.put("status", cursor.getString(3).toString());
                dataList.add(mapToday);
                cursor.moveToNext();
            }
        }
    }

    public void loadListView(NoScrollListView listView, final ArrayList<HashMap<String, String>> dataList) {
        ListTaskAdapter adapter = new ListTaskAdapter(this, dataList, mydb);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                Intent i = new Intent(MainActivity.this, AddModifyTask.class);
                i.putExtra("isModify", true);
                i.putExtra("id", dataList.get(+position).get("id"));
                startActivity(i);
            }
        });
    }
}

Finally my AndroidManifest.xml looks like below.

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/CustomTheme">
        <activity android:name=".AddModifyTask"
            android:windowSoftInputMode="adjustResize"></activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Now you can Run the project. Some icons like Calendar & Delete I have used in this project, you can download the source code and find them under the drawable directory. Or you can directly download them from GitHub.