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 AndroidSize: 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.
id | task | task_at | status |
1 | Task Details 1 | dd/MM/yyyy | 1 |
2 | Task Details 2 | dd/MM/yyyy | 0 |
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.