13 29 Singleton
At this stage our JavaFX to-do list has a working basic interface, but it is not very useful yet: the user can only see a few hard-coded tasks and cannot add their own. They also expect their items to still be there the next time they launch the app. To make that work, we will add a small layer that loads and saves the to-do items in a flat file.
The Application class our Main extends from has a stop() method we can override to save data when the application closes. The controller needs the data to populate the list and also has direct access to its contents when we want to store them. Because both the main class and the controller need to access the same data, we use a singleton: a class that has only one instance during the lifetime of the application, with a private constructor so nothing else can create more instances, and a static method to return that single instance.
Creating the TodoData singleton
Inside the datamodel package we create a new class TodoData. We define a unique instance, a file name where the data will be stored, the in-memory list of items and a date formatter:
public class TodoData {
private static final TodoData instance = new TodoData();
private static final String filename = "TodoListItems.txt";
private List<TodoItem> todoItems;
private DateTimeFormatter formatter;
public static TodoData getInstance() { return instance; }
private TodoData() {
formatter = DateTimeFormatter.ofPattern("MMM d, yyyy");
}
public List<TodoItem> getTodoItems() { return todoItems; }
public void setTodoItems(List<TodoItem> items) { this.todoItems = items; }
}
The constructor is private, which is what makes the class a singleton. The static method getInstance() is the only way for the rest of the app — main class and controller — to reach our data.
Loading items from a file
We add a method that reads the items from disk. We use the older try / finally style here for clarity:
public void loadTodoItems() throws IOException {
todoItems = FXCollections.observableArrayList();
Path path = Paths.get(filename);
// open a BufferedReader and read each line here
}
FXCollections.observableArrayList() gives us a JavaFX-friendly list that the ListView can later react to. We will continue this method in the next video by setting up a BufferedReader and parsing each line into a TodoItem. See you soon.