13 31 Loading and saving TodoItems
Before we move on, let us recap a couple of things we just used. In the TodoData singleton we declared the items as an ObservableList instead of a plain list. The reason is that the ListView in our controller calls setAll(...), which expects an ObservableList. We build it with FXCollections.observableArrayList() from the javafx.collections package and then add our TodoItems to it. That gives JavaFX the right type so the ListView can later react to changes.
Reading the file is done with the Path API. We grab the path, open a BufferedReader and parse each line into a TodoItem. To hook this code to the application life cycle we move to the main class and override the stop() method. JavaFX calls stop() when the user closes the main window, which is exactly when we want to persist data.
Overriding init and stop
Using Alt + Insert > Override Methods we pick stop, remove the call to super and wrap the body in a try/catch. Inside the try we grab the singleton with TodoData.getInstance() and call storeTodoItems(). To bootstrap the data file we also keep a temporary call in the controller's initialize method so the first run writes our hard-coded items to disk, then we close the app to trigger stop() and verify the text file lands at the root of the IntelliJ project.
- Override
stop()to save the list when the window is closed. - Override
init()in the same way and callloadTodoItems()so the data is loaded when the app starts. - Once it works, the hard-coded items in the controller can be removed.
Because init() is invoked automatically by JavaFX at startup, the singleton now ends up populated from the file on every launch. In the next video we clean up the controller and rely entirely on the file as the source of truth.
Summary
This lesson covers implementing file persistence for JavaFX TodoList applications using ObservableArrayList and the singleton pattern. You'll learn how to override the main class's stop() method to save items automatically when users close the application, and the init() method to load items on startup, replacing hardcoded data with actual file-based storage using Path and BufferedReader APIs.
Key points
- Use JavaFX FXCollections.observableArrayList to maintain list compatibility with UI components like ListView
- Override the main class's stop() method to persist TodoItems automatically when the application closes
- Override the init() method to load persisted TodoItems on application startup, eliminating hardcoded data
- Implement the singleton pattern (TodoData.getInstance()) to maintain a single data instance across the entire application
- Wrap file I/O operations in try-catch blocks to handle potential exceptions gracefully
- Store data in plain text files created in the project root directory for simple persistence
FAQ
Why must we use ObservableArrayList instead of a regular ArrayList?
ObservableArrayList is required because JavaFX ListView components automatically track changes to the underlying collection. Using FXCollections.observableArrayList ensures the UI automatically updates whenever items are added, removed, or modified without manual refresh calls.
What's the difference between the init() and stop() methods in JavaFX applications?
The init() method is called by JavaFX when the application starts, making it the ideal place to load persisted data from files. The stop() method is called when the user closes the application window, providing the opportunity to save all current changes before shutdown.
How does the singleton pattern improve data persistence in this architecture?
The singleton pattern (TodoData.getInstance()) ensures only one instance of the data class exists throughout the application's lifetime. This guarantees all application components access and modify the same dataset consistently, preventing data conflicts and ensuring that loaded and saved data remain in sync across the entire application.