This book dives deep into the Architecture Components, showing you how they work individually and in concert. With over a dozen sample projects, the book covers much of what blog posts miss, in terms of how to make this library work in practice. Android app development can be divided into two generations: • First-generation app development uses Java as the programming language and leverages the Android Support Library and the android.arch edition of the Architecture Components • Second-generation app development more often uses Kotlin as the programming language and leverages AndroidX and the rest of Jetpack (which includes an AndroidX edition of the Architecture Components) This book is a first-generation book. It explores the android.arch edition of the Architecture Components and it uses Java for most of the examples. Second-generation material can be found in CommonsWare’s “Elements” book series. Of particular note, some introductory Architecture Components material can be found in Elements of Android Jetpack. I am in the process of wrapping up my books that focused on the first generation of Android app development (Java and the Android Support Library), in favor of books focusing on the second generation (Kotlin and Jetpack/AndroidX). The first of the original books to be marked “FINAL” is Android’s Architecture Components. Table of Contents Preface First-Generation Book Prerequisites Source Code and Its License Creative Commons and the Four-to-Free (42F) Guarantee Acknowledgments Room Basics Wrenching Relations Into Objects Room Requirements Room Furnishings Entities DAO Database Get a Room Testing Room Writing Instrumentation Tests Using In-Memory Databases Importing Starter Data Writing Unit Tests via Mocks The Dao of Entities Configuring Entities Primary Keys Auto-Generated Primary Keys Composite Primary Keys Adding Indexes Ignoring Fields NOT NULL Fields Custom Table and Column Names Other @ColumnInfo Options Indexing Collation Type Affinity DAOs and Queries Adding Parameters WHERE Clause Other Clauses What You Can Return Specific Return Types Breadth of Results Aggregate Functions Dynamic Queries query() @RawQuery Other DAO Operations Parameters Return Values Conflict Resolution Other Operations Transactions and Room Using @Transaction Custom Methods On @Query Methods Using RoomDatabase Threads and Room Room and Custom Types Type Converters Setting Up a Type Converter Example: Dates and Times Example: Locations Example: Simple Collections Embedded Types Example: Locations Simple vs. Prefixed Updating the Trip Sample Room and Relations The Classic ORM Approach A History of Threading Mistakes The Room Approach No Direct Entity References Foreign Keys Cascades on Updates and Deletes Cascades on... Retrievals? Plans for Trips The Domain Model The New Entities The Updated DAO and Database Self-Referential Relations for Tree Structures Using @Relation @Relation and @Query Representing No Relation The Support Database API “Can’t You See That This is a Facade?” Requery CWAC-SafeRoom AssetRoom Other ORMs When Will We Use This? Configuring Room’s Database Access Get a Factory Add a Callback Room and Migrations What’s a Migration? When Do We Migrate? But First, a Word About Exporting Schemas Writing Migrations Employing Migrations How Room Applies Migrations Testing Migrations Adding the Artifact Adding the Schemas Creating and Using a MigrationTestHelper Adding the Rule Setting Up the Helper Creating a Database for a Schema Version Testing a Migration Lifecycles and Owners A Tale of Terminology Lifecycle Lifecycle Owner Lifecycle Observers Adding the Lifecycle Components Getting a Lifecycle ...From a FragmentActivity or a Support Fragment ...From an AppCompatActivity ...From an Activity or Fragment ...From Anything Else Observing a Lifecycle Legacy Options Ordinary Activities and Fragments, and Other Objects Pre-Java 8 So, What’s the Point of This? LiveData Observables Are the New Black Yet More Terminology LiveData Observer Active State Implementing LiveData Dependencies State Transitions Updating the Observers Retaining the LiveData Other LiveData Examples Event Bus Room ViewModel Viewmodels, As Originally Envisioned ViewModel Versus... ...Saved Instance State ...Retained Objects Dependencies Mommy, Where Does a ViewModel Come From? ViewModel In Action Defining a ViewModel Getting a ViewModel Using the ViewModel Getting Rid of the ViewModel Other Lifecycle Owners LifecycleService ProcessLifecycleOwner Wait... Where Are LifecycleProvider and LifecycleReceiver? LiveData and Data Binding A Data Binding Recap New Layout Resource Structure Binding Expressions Adapters Binding from Code Observable Data Sources LiveData Updating Data Binding Updating Observables Binding to LiveData Handling Changes to LiveData The Saved Instance State Situation Existing Model New Model WorkManager Where Should We Use WorkManager? Where Should We Not Use WorkManager? WorkManager Dependencies Workers: They Do Work Performing Simple Work Work Inputs Constrained Work Tagged Work Monitoring Work Getting the Status Updates Consuming the Status Updates... In Code Consuming the Status Updates... In Data Binding Canceling Work Delayed Work Parallel Work Chained Work Why? How Do We Chain Work? How Do We Pass Data Along the Chain? OK, Where’s the Code? How Complex Can This Get? Periodic Work Unique Work Testing Work WorkManager and Side Effects M:N Relations in Room Implementing a Join Entity Static Entity Classes Foreign Keys and Indices Implementing DAO Methods Adding and Removing Relations Fetching Via the Join Where’s That Good Ol’ Object Feel? Polymorphic Room Relations Polymorphism With Separate Tables Can I Join a UNION? Polymorphism With a Single Table Polymorphism With M:N Relations LiveData Transformations The Bucket Brigade Mapping Data to Data Mapping Data to... LiveData? Writing a Transformation Do We Really Want This? RxJava and Room Adding RxJava Decisions, Decisions One-Time or Ongoing? Zero, One, or N? The One-Time Option: Single Item Singles List Singles The One-Time 0-1 Option: Maybe The Ongoing Option: Flowable Item Flowables List Flowables @RawQuery and Reactive Responses RxJava and Lifecycles The Classic Approach Bridging RxJava and LiveData From RxJava to LiveData From LiveData to RxJava The Uber Solution: AutoDispose Packing Up a Room The Problem The Classic Solution: SQLiteAssetHelper The New Problem Merging SQLiteAssetHelper with Room Paging Room Data The Problem: Too Much Data Addressing the UX Enter the Paging Library PagedList PagedListAdapter DataSource.Factory LivePagedListProvider Paging and Room The Dependency The Entity, DAO, and Database The ViewModel The PagedListAdapter The CitiesFragment The Results What About RxJava? LiveData and Bound Services Old API, New Coat of Paint Remote Sensors The AIDL The Service and the Process The LiveData and the ViewModel The Activity and the Layout Immutability The Benefits of Immutability No Dirty Data Thread Safety Functional Programming The Costs of Immutability Partial Immutability Problems Some Things Want Setters Garbage, To Be Collected Immutability via AutoValue AutoValue and LiveData AutoValue and Room The Repository Pattern What the Repository Does Manages Data Storage Normalizes Model Objects Provides a Clean Reactive API Isolates Rest of App from Strategy Changes High-Level Repository Strategies Pure Network Network + Network API Caching Network + External Caching Network + First-Class Persistence Persistence-Only Let’s Roll the Dice The Repository API Implementation The ViewModel Repository Integration Saving State The Factory The Fragment The UI The Menu The Event Flow Blending Data Sources Pwned Passwords PwnedCheck score() validate() Adding OkHttp and INTERNET Integrating PwnedCheck Modifying the Model Validating the Passphrase Introducing Model-View-Intent GUI Architectures Why People Worry About GUI Architectures Avoiding Known Problems Consistency Between Team Members Consistency Over Time Why Others Ignore GUI Architectures Atypical Apps YAGNI and Overhead No Obvious User Benefit No Consistency In Definitions A Rough Comparison of GUI Architectures The Basics of Model-View-Intent What’s a View State? What’s a Reducer? Where Does the “Intent” Thing Show Up? Additional MVI Resources A Deep Dive Into MVI What the Sample App Does The Roster The Viewer The Editor MVI and the Sample App The Model The View State The View Incorporating a ViewModel Receiving View States Rendering View States The Actions Publishing Actions The Repositories ToDoRepository FilterModeRepository The Controller Subscribing to Actions Doing the Work and Publishing Results add()/modify()/delete() filter() select()/unselect()/unselectAll() load() About Those Results The Reducer in the RosterViewModel Subscribing to Results Merging Results Into the ViewState Examining the Other Fragments DisplayFragment EditFragment Summary Backing Up a Room What Do We Need to Back Up? Plan A: The Whole Directory Plan B: Just SQLite’s Files Beware of Open Rooms When Do We Back Up the Database? When the User Asks When You Feel Like It When You Think Room Is Not Using It A Simple Close The Nuclear Option A Basic Backup Example Triggering the Operation Our UI Performing the Operation Areas for Improvement Backing Up Off-Device Room and Full-Text Searching What Is FTS? The Room 1.x FTS Recipe Manually Create the Table RawQuery the Table Searching a Book The Book The Data Model The Database The Searches The Repository The ViewModels The UI The Results Room and Conflict Resolution Abort What SQLite Does Effects in Room Fail What SQLite Does Effects in Room Ignore What SQLite Does Effects in Room Replace What SQLite Does Effects in Room Rollback What SQLite Does Effects in Room What Should You Use with Room? Configuring SQLite Beyond Room When To Make Changes Example: Turbo Boost Mode