1efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar/* 2efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * Copyright (C) 2016 The Android Open Source Project 3efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * 4efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * you may not use this file except in compliance with the License. 6efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * You may obtain a copy of the License at 7efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * 8efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * 10efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * See the License for the specific language governing permissions and 14efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar * limitations under the License. 15efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar */ 16efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar 17ba069d50913c3fb250bb60ec310439db36895337Alan Viverettepackage androidx.room; 1864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar 192eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Arakiimport android.annotation.SuppressLint; 202eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Arakiimport android.app.ActivityManager; 21059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyarimport android.content.Context; 22efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyarimport android.database.Cursor; 232eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Arakiimport android.os.Build; 24a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport android.util.Log; 25efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar 26ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.CallSuper; 27ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.NonNull; 28ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.Nullable; 29ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.RequiresApi; 30ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.RestrictTo; 31ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.annotation.WorkerThread; 32ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.collection.SparseArrayCompat; 33ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.core.app.ActivityManagerCompat; 34ddee2b5170ae257a7b2494f8aaa8459ebed806dcAurimas Liutikasimport androidx.arch.core.executor.ArchTaskExecutor; 35ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.room.migration.Migration; 36ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SimpleSQLiteQuery; 37ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteDatabase; 38ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteOpenHelper; 39ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteQuery; 40ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.SupportSQLiteStatement; 41ba069d50913c3fb250bb60ec310439db36895337Alan Viveretteimport androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory; 42ba069d50913c3fb250bb60ec310439db36895337Alan Viverette 43a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.util.ArrayList; 44a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.util.Collections; 45d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapardimport java.util.HashSet; 46a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyarimport java.util.List; 47d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapardimport java.util.Set; 4864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Arakiimport java.util.concurrent.Callable; 495843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Arakiimport java.util.concurrent.locks.Lock; 505843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Arakiimport java.util.concurrent.locks.ReentrantLock; 51efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar 52efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar/** 53e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * Base class for all Room databases. All classes that are annotated with {@link Database} must 54e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * extend this class. 55e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * <p> 56e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * RoomDatabase provides direct access to the underlying database implementation but you should 57e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * prefer using {@link Dao} classes. 58e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * 59e69e470336d0b6a1b4a16fe1783af17143d0c426Sergey Vasilinets * @see Database 60efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar */ 61e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets//@SuppressWarnings({"unused", "WeakerAccess"}) 62937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyarpublic abstract class RoomDatabase { 63059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar private static final String DB_IMPL_SUFFIX = "_Impl"; 646bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar /** 656bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar * Unfortunately, we cannot read this value so we are only setting it to the SQLite default. 666bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar * 676bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar * @hide 686bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar */ 696bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 706bbf7089c9d4050b04ad48e1a1e5e2c713c48840Yigit Boyar public static final int MAX_BIND_PARAMETER_CNT = 999; 71fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar // set by the generated open helper. 72fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar protected volatile SupportSQLiteDatabase mDatabase; 73059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar private SupportSQLiteOpenHelper mOpenHelper; 7434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar private final InvalidationTracker mInvalidationTracker; 752e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar private boolean mAllowMainThreadQueries; 762eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki boolean mWriteAheadLoggingEnabled; 77efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar 78cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki @Nullable 79cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki protected List<Callback> mCallbacks; 80cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki 815843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki private final ReentrantLock mCloseLock = new ReentrantLock(); 825843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki 835843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki /** 845843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki * {@link InvalidationTracker} uses this lock to prevent the database from closing while it is 855843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki * querying database updates. 865843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki * 875843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki * @return The lock for {@link #close()}. 885843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki */ 895843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki Lock getCloseLock() { 905843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki return mCloseLock; 915843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki } 925843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki 93d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar /** 94059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * Creates a RoomDatabase. 95059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * <p> 96059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * You cannot create an instance of a database, instead, you should acquire it via 97059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * {@link Room#databaseBuilder(Context, Class, String)} or 98059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * {@link Room#inMemoryDatabaseBuilder(Context, Class)}. 99059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar */ 100059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar public RoomDatabase() { 10134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar mInvalidationTracker = createInvalidationTracker(); 102059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 103059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 104059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar /** 105059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * Called by {@link Room} when it is initialized. 106d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * 107059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * @param configuration The database configuration. 108d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar */ 109059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar @CallSuper 110cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets public void init(@NonNull DatabaseConfiguration configuration) { 111d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar mOpenHelper = createOpenHelper(configuration); 1122eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki boolean wal = false; 1132eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 1142eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki wal = configuration.journalMode == JournalMode.WRITE_AHEAD_LOGGING; 1152eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mOpenHelper.setWriteAheadLoggingEnabled(wal); 1162eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 117cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki mCallbacks = configuration.callbacks; 1182e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar mAllowMainThreadQueries = configuration.allowMainThreadQueries; 1192eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mWriteAheadLoggingEnabled = wal; 120d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar } 121d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar 122d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar /** 123d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Returns the SQLite open helper used by this database. 124d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * 125d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * @return The SQLite open helper used by this database. 126d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar */ 127cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets @NonNull 128d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar public SupportSQLiteOpenHelper getOpenHelper() { 129d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar return mOpenHelper; 130efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar } 131d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar 132d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar /** 133d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Creates the open helper to access the database. Generated class already implements this 134d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * method. 135d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * Note that this method is called when the RoomDatabase is initialized. 136d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * 137d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * @param config The configuration of the Room database. 138d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * @return A new SupportSQLiteOpenHelper to be used while connecting to the database. 139d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar */ 140cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets @NonNull 141d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar protected abstract SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config); 142d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar 14334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar /** 14434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Called when the RoomDatabase is created. 14534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * <p> 14634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * This is already implemented by the generated code. 14734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * 14834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * @return Creates a new InvalidationTracker. 14934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar */ 150cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets @NonNull 15134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar protected abstract InvalidationTracker createInvalidationTracker(); 15234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar 153fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar /** 154fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki * Deletes all rows from all the tables that are registered to this database as 155fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki * {@link Database#entities()}. 156fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki * <p> 157fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki * This does NOT reset the auto-increment value generated by {@link PrimaryKey#autoGenerate()}. 1587a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki * <p> 1597a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki * After deleting the rows, Room will set a WAL checkpoint and run VACUUM. This means that the 1607a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki * data is completely erased. The space will be reclaimed by the system if the amount surpasses 1617a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki * the threshold of database file size. 1627a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki * 1637a8b4c9ce824dff0416525ec33302d228901c899Yuichi Araki * @see <a href="https://www.sqlite.org/fileformat.html">Database File Format</a> 164fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki */ 165fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki @WorkerThread 166fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki public abstract void clearAllTables(); 167fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki 168fe072103d888dcd93ed30302b9e50e4211458057Yuichi Araki /** 169489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar * Returns true if database connection is open and initialized. 170fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar * 171489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar * @return true if the database connection is open, false otherwise. 172fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar */ 173489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar public boolean isOpen() { 174489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar final SupportSQLiteDatabase db = mDatabase; 175489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar return db != null && db.isOpen(); 176489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar } 177489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar 178489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar /** 179489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar * Closes the database if it is already open. 180489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar */ 181489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar public void close() { 182489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar if (isOpen()) { 1835843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki try { 1845843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki mCloseLock.lock(); 1855843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki mOpenHelper.close(); 1865843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki } finally { 1875843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki mCloseLock.unlock(); 1885843a353d7d4740a2d6119fdd90f258f645f4f20Yuichi Araki } 189489d61a70a742408cda5ca1a4d9788b9f14282a0Yigit Boyar } 190fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar } 191fa3905934508aa143d899cb9b62b3b074748c9e9Yigit Boyar 1922e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar /** 1932e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * Asserts that we are not on the main thread. 1942e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * 1952e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * @hide 1962e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar */ 197e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @SuppressWarnings("WeakerAccess") 1982e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 199e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets // used in generated code 2002e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar public void assertNotMainThread() { 2012e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar if (mAllowMainThreadQueries) { 2022e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar return; 2032e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar } 204ae36c8b11a64d3cdc9ba6e37d9f3d1d250fdc4a8Yigit Boyar if (ArchTaskExecutor.getInstance().isMainThread()) { 2052e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar throw new IllegalStateException("Cannot access database on the main thread since" 20618f17f79daecd759ec66a2d2d7bf551542fcda4aFlorina Muntenescu + " it may potentially lock the UI for a long period of time."); 2072e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar } 2082e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar } 2092e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar 210937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar // Below, there are wrapper methods for SupportSQLiteDatabase. This helps us track which 211937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar // methods we are using and also helps unit tests to mock this class without mocking 212a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar // all SQLite database methods. 213059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 214937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar /** 215e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar * Convenience method to query the database with arguments. 216937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * 217e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar * @param query The sql query 218e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar * @param args The bind arguments for the placeholders in the query 219e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar * 220e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar * @return A Cursor obtained by running the given query in the Room database. 221937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar */ 222e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar public Cursor query(String query, @Nullable Object[] args) { 223e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar return mOpenHelper.getWritableDatabase().query(new SimpleSQLiteQuery(query, args)); 224efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar } 225efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar 226937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar /** 227e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar * Wrapper for {@link SupportSQLiteDatabase#query(SupportSQLiteQuery)}. 228b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * 229a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * @param query The Query which includes the SQL and a bind callback for bind arguments. 230b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * @return Result of the query. 231b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar */ 232b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar public Cursor query(SupportSQLiteQuery query) { 2332e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar assertNotMainThread(); 234e185ed6ba937bdc218104c18d2615e1ce524adb7Yigit Boyar return mOpenHelper.getWritableDatabase().query(query); 235b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar } 236b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar 237b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar /** 238937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Wrapper for {@link SupportSQLiteDatabase#compileStatement(String)}. 239937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * 240937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * @param sql The query to compile. 241937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * @return The compiled query. 242937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar */ 243cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets public SupportSQLiteStatement compileStatement(@NonNull String sql) { 2442e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar assertNotMainThread(); 245d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar return mOpenHelper.getWritableDatabase().compileStatement(sql); 246291985054e698c918df1c735d1042b63b9e97219Yigit Boyar } 247291985054e698c918df1c735d1042b63b9e97219Yigit Boyar 248937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar /** 249937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Wrapper for {@link SupportSQLiteDatabase#beginTransaction()}. 250937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar */ 251291985054e698c918df1c735d1042b63b9e97219Yigit Boyar public void beginTransaction() { 2522e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar assertNotMainThread(); 253458885cbb4677ae06ce3bd0c4172c86928a7b101Yuichi Araki SupportSQLiteDatabase database = mOpenHelper.getWritableDatabase(); 254458885cbb4677ae06ce3bd0c4172c86928a7b101Yuichi Araki mInvalidationTracker.syncTriggers(database); 255458885cbb4677ae06ce3bd0c4172c86928a7b101Yuichi Araki database.beginTransaction(); 256291985054e698c918df1c735d1042b63b9e97219Yigit Boyar } 257291985054e698c918df1c735d1042b63b9e97219Yigit Boyar 258937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar /** 259937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Wrapper for {@link SupportSQLiteDatabase#endTransaction()}. 260937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar */ 261291985054e698c918df1c735d1042b63b9e97219Yigit Boyar public void endTransaction() { 262d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar mOpenHelper.getWritableDatabase().endTransaction(); 2639610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar if (!inTransaction()) { 2649610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar // enqueue refresh only if we are NOT in a transaction. Otherwise, wait for the last 2659610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar // endTransaction call to do it. 2669610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar mInvalidationTracker.refreshVersionsAsync(); 2679610cdd0c0def94a85f4b537d05e4b3226cec3b0Yigit Boyar } 268291985054e698c918df1c735d1042b63b9e97219Yigit Boyar } 269291985054e698c918df1c735d1042b63b9e97219Yigit Boyar 270937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar /** 271937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar * Wrapper for {@link SupportSQLiteDatabase#setTransactionSuccessful()}. 272937a77cef9380b6e03e9e3177a563ddcc4fd1fb5Yigit Boyar */ 273291985054e698c918df1c735d1042b63b9e97219Yigit Boyar public void setTransactionSuccessful() { 274d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar mOpenHelper.getWritableDatabase().setTransactionSuccessful(); 275efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar } 276059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 277059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar /** 27864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * Executes the specified {@link Runnable} in a database transaction. The transaction will be 27964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * marked as successful unless an exception is thrown in the {@link Runnable}. 28064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * 28164cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * @param body The piece of code to execute. 28264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki */ 283cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets public void runInTransaction(@NonNull Runnable body) { 28464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki beginTransaction(); 28564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki try { 28664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki body.run(); 28764cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki setTransactionSuccessful(); 28864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } finally { 28964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki endTransaction(); 29064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } 29164cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } 29264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki 29364cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki /** 29464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * Executes the specified {@link Callable} in a database transaction. The transaction will be 29564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * marked as successful unless an exception is thrown in the {@link Callable}. 29664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * 29764cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * @param body The piece of code to execute. 29864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * @param <V> The type of the return value. 29964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki * @return The value returned from the {@link Callable}. 30064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki */ 301cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets public <V> V runInTransaction(@NonNull Callable<V> body) { 30264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki beginTransaction(); 30364cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki try { 30464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki V result = body.call(); 30564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki setTransactionSuccessful(); 30664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki return result; 30764cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } catch (RuntimeException e) { 30864cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki throw e; 30964cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } catch (Exception e) { 31064cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki throw new RuntimeException("Exception in transaction", e); 31164cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } finally { 31264cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki endTransaction(); 31364cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } 31464cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki } 31564cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki 31664cba1f9990a73204dda5f24fdbf249926acc2e0Yuichi Araki /** 31734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Called by the generated code when database is open. 31834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * <p> 31934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * You should never call this method manually. 32034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * 32134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * @param db The database instance. 32234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar */ 323cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets protected void internalInitInvalidationTracker(@NonNull SupportSQLiteDatabase db) { 32434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar mInvalidationTracker.internalInit(db); 32534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar } 32634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar 32734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar /** 32834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Returns the invalidation tracker for this database. 32934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * <p> 33034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * You can use the invalidation tracker to get notified when certain tables in the database 33134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * are modified. 33234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * 33334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * @return The invalidation tracker for the database. 33434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar */ 335cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets @NonNull 33634e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar public InvalidationTracker getInvalidationTracker() { 33734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar return mInvalidationTracker; 33834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar } 33934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar 34034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar /** 34134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * Returns true if current thread is in a transaction. 34234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * 34334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * @return True if there is an active transaction in current thread, false otherwise. 34434e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * @see SupportSQLiteDatabase#inTransaction() 34534e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar */ 346e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @SuppressWarnings("WeakerAccess") 34734e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar public boolean inTransaction() { 34834e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar return mOpenHelper.getWritableDatabase().inTransaction(); 34934e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar } 35034e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar 35134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar /** 3522eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * Journal modes for SQLite database. 3532eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * 3542eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * @see RoomDatabase.Builder#setJournalMode(JournalMode) 3552eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki */ 3562eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki public enum JournalMode { 3572eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki 3582eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki /** 3592eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * Let Room choose the journal mode. This is the default value when no explicit value is 3602eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * specified. 3612eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * <p> 3622eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * The actual value will be {@link #TRUNCATE} when the device runs API Level lower than 16 3632eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * or it is a low-RAM device. Otherwise, {@link #WRITE_AHEAD_LOGGING} will be used. 3642eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki */ 3652eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki AUTOMATIC, 3662eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki 3672eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki /** 3682eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * Truncate journal mode. 3692eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki */ 3702eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki TRUNCATE, 3712eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki 3722eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki /** 3732eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * Write-Ahead Logging mode. 3742eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki */ 3752eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki @RequiresApi(Build.VERSION_CODES.JELLY_BEAN) 3762eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki WRITE_AHEAD_LOGGING; 3772eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki 3782eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki /** 3792eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * Resolves {@link #AUTOMATIC} to either {@link #TRUNCATE} or 3802eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * {@link #WRITE_AHEAD_LOGGING}. 3812eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki */ 3822eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki @SuppressLint("NewApi") 3832eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki JournalMode resolve(Context context) { 3842eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki if (this != AUTOMATIC) { 3852eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki return this; 3862eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 3872eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 3882eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki ActivityManager manager = (ActivityManager) 3892eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki context.getSystemService(Context.ACTIVITY_SERVICE); 3902eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki if (manager != null && !ActivityManagerCompat.isLowRamDevice(manager)) { 3912eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki return WRITE_AHEAD_LOGGING; 3922eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 3932eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 3942eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki return TRUNCATE; 3952eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 3962eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 3972eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki 3982eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki /** 399059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * Builder for RoomDatabase. 400059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * 401059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * @param <T> The type of the abstract database class. 402059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar */ 403059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar public static class Builder<T extends RoomDatabase> { 404059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar private final Class<T> mDatabaseClass; 405059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar private final String mName; 406059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar private final Context mContext; 407cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki private ArrayList<Callback> mCallbacks; 408059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 409059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar private SupportSQLiteOpenHelper.Factory mFactory; 4102e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar private boolean mAllowMainThreadQueries; 4112eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki private JournalMode mJournalMode; 412234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar private boolean mRequireMigration; 413a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar /** 414a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * Migrations, mapped by from-to pairs. 415a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar */ 416d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard private final MigrationContainer mMigrationContainer; 417d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard private Set<Integer> mMigrationsNotRequiredFrom; 418d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard /** 419d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * Keeps track of {@link Migration#startVersion}s and {@link Migration#endVersion}s added in 420d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * {@link #addMigrations(Migration...)} for later validation that makes those versions don't 421eed1cacab66988de500612cf4c6af3bcb80402efshepshapard * match any versions passed to {@link #fallbackToDestructiveMigrationFrom(int...)}. 422d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard */ 423d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard private Set<Integer> mMigrationStartAndEndVersions; 424059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 425059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar Builder(@NonNull Context context, @NonNull Class<T> klass, @Nullable String name) { 426059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar mContext = context; 427059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar mDatabaseClass = klass; 428059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar mName = name; 4292eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mJournalMode = JournalMode.AUTOMATIC; 430234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar mRequireMigration = true; 431a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar mMigrationContainer = new MigrationContainer(); 432059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 433059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 434059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar /** 435059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * Sets the database factory. If not set, it defaults to 436059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * {@link FrameworkSQLiteOpenHelperFactory}. 437059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * 438059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * @param factory The factory to use to access the database. 439059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * @return this 440059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar */ 441e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @NonNull 442e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets public Builder<T> openHelperFactory(@Nullable SupportSQLiteOpenHelper.Factory factory) { 443059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar mFactory = factory; 444059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar return this; 445059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 446059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 447059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar /** 448a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * Adds a migration to the builder. 449a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * <p> 450a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * Each Migration has a start and end versions and Room runs these migrations to bring the 451a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * database to the latest version. 452a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * <p> 453a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * If a migration item is missing between current version and the latest version, Room 454a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * will clear the database and recreate so even if you have no changes between 2 versions, 455a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * you should still provide a Migration object to the builder. 456a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * <p> 457a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * A migration can handle more than 1 version (e.g. if you have a faster path to choose when 458a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * going version 3 to 5 without going to version 4). If Room opens a database at version 459a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * 3 and latest version is >= 5, Room will use the migration object that can migrate from 460a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * 3 to 5 instead of 3 to 4 and 4 to 5. 461a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * 462a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * @param migrations The migration object that can modify the database and to the necessary 463a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * changes. 464059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * @return this 465059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar */ 466e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @NonNull 467d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard public Builder<T> addMigrations(@NonNull Migration... migrations) { 468d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard if (mMigrationStartAndEndVersions == null) { 469d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard mMigrationStartAndEndVersions = new HashSet<>(); 470d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 471d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard for (Migration migration: migrations) { 472d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard mMigrationStartAndEndVersions.add(migration.startVersion); 473d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard mMigrationStartAndEndVersions.add(migration.endVersion); 474d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 475d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard 476a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar mMigrationContainer.addMigrations(migrations); 477059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar return this; 478059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 479059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar 480059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar /** 4812e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * Disables the main thread query check for Room. 4822e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * <p> 4832e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * Room ensures that Database is never accessed on the main thread because it may lock the 4842e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * main thread and trigger an ANR. If you need to access the database from the main thread, 4852e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * you should always use async alternatives or manually move the call to a background 4862e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * thread. 4872e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * <p> 4882e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * You may want to turn this check off for testing. 4892e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * 4902e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar * @return this 4912e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar */ 492e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @NonNull 4932e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar public Builder<T> allowMainThreadQueries() { 4942e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar mAllowMainThreadQueries = true; 4952e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar return this; 4962e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar } 4972e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar 4982e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar /** 4992eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * Sets the journal mode for this database. 5002eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * 5012eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * <p> 5022eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * This value is ignored if the builder is initialized with 5032eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * {@link Room#inMemoryDatabaseBuilder(Context, Class)}. 5042eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * <p> 5052eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * The journal mode should be consistent across multiple instances of 5062eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * {@link RoomDatabase} for a single SQLite database file. 5072eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * <p> 5082eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * The default value is {@link JournalMode#AUTOMATIC}. 5092eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * 5102eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * @param journalMode The journal mode. 5112eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki * @return this 5122eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki */ 5132eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki @NonNull 5142eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki public Builder<T> setJournalMode(@NonNull JournalMode journalMode) { 5152eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mJournalMode = journalMode; 5162eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki return this; 5172eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki } 5182eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki 5192eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki /** 520ff860035ea975be71d875a31591c30d8bdcb6a9dshepshapard * Allows Room to destructively recreate database tables if {@link Migration}s that would 521ff860035ea975be71d875a31591c30d8bdcb6a9dshepshapard * migrate old database schemas to the latest schema version are not found. 522ff860035ea975be71d875a31591c30d8bdcb6a9dshepshapard * <p> 523234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * When the database version on the device does not match the latest schema version, Room 524234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * runs necessary {@link Migration}s on the database. 525234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * <p> 526234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * If it cannot find the set of {@link Migration}s that will bring the database to the 527234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * current version, it will throw an {@link IllegalStateException}. 528234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * <p> 529234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * You can call this method to change this behavior to re-create the database instead of 530234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * crashing. 531234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * <p> 532234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * Note that this will delete all of the data in the database tables managed by Room. 533234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * 534234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar * @return this 535234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar */ 536e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @NonNull 537234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar public Builder<T> fallbackToDestructiveMigration() { 538234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar mRequireMigration = false; 539234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar return this; 540234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar } 541234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar 542234f073e2227fcb62a9ed8285c79724de1f0fa92Yigit Boyar /** 543d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * Informs Room that it is allowed to destructively recreate database tables from specific 544d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * starting schema versions. 545d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * <p> 546d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * This functionality is the same as that provided by 547d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * {@link #fallbackToDestructiveMigration()}, except that this method allows the 548d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * specification of a set of schema versions for which destructive recreation is allowed. 549d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * <p> 550d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * Using this method is preferable to {@link #fallbackToDestructiveMigration()} if you want 551d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * to allow destructive migrations from some schema versions while still taking advantage 552d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * of exceptions being thrown due to unintentionally missing migrations. 553d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * <p> 554d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * Note: No versions passed to this method may also exist as either starting or ending 555d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * versions in the {@link Migration}s provided to {@link #addMigrations(Migration...)}. If a 556d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * version passed to this method is found as a starting or ending version in a Migration, an 557d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * exception will be thrown. 558d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * 559d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * @param startVersions The set of schema versions from which Room should use a destructive 560d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * migration. 561d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard * @return this 562d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard */ 563d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard @NonNull 564eed1cacab66988de500612cf4c6af3bcb80402efshepshapard public Builder<T> fallbackToDestructiveMigrationFrom(int... startVersions) { 565d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard if (mMigrationsNotRequiredFrom == null) { 566eed1cacab66988de500612cf4c6af3bcb80402efshepshapard mMigrationsNotRequiredFrom = new HashSet<>(startVersions.length); 567eed1cacab66988de500612cf4c6af3bcb80402efshepshapard } 568eed1cacab66988de500612cf4c6af3bcb80402efshepshapard for (int startVersion : startVersions) { 569eed1cacab66988de500612cf4c6af3bcb80402efshepshapard mMigrationsNotRequiredFrom.add(startVersion); 570d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 571d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard return this; 572d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 573d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard 574d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard /** 575cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * Adds a {@link Callback} to this database. 576cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * 577cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * @param callback The callback. 578cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * @return this 579cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki */ 580e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @NonNull 581cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki public Builder<T> addCallback(@NonNull Callback callback) { 582cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki if (mCallbacks == null) { 583cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki mCallbacks = new ArrayList<>(); 584cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki } 585cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki mCallbacks.add(callback); 586cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki return this; 587cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki } 588cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki 589cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki /** 590059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * Creates the databases and initializes it. 59134e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * <p> 59234e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * By default, all RoomDatabases use in memory storage for TEMP tables and enables recursive 59334e5031083f735db3a395b0f6aa430880b072d71Yigit Boyar * triggers. 59464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar * 595059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar * @return A new database instance. 596059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar */ 597e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @NonNull 598059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar public T build() { 599059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar //noinspection ConstantConditions 600059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar if (mContext == null) { 601059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar throw new IllegalArgumentException("Cannot provide null context for the database."); 602059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 603059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar //noinspection ConstantConditions 604059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar if (mDatabaseClass == null) { 605059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar throw new IllegalArgumentException("Must provide an abstract class that" 606059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar + " extends RoomDatabase"); 607059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 608d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard 609d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard if (mMigrationStartAndEndVersions != null && mMigrationsNotRequiredFrom != null) { 610d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard for (Integer version : mMigrationStartAndEndVersions) { 611d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard if (mMigrationsNotRequiredFrom.contains(version)) { 612d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard throw new IllegalArgumentException( 613d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard "Inconsistency detected. A Migration was supplied to " 614d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard + "addMigration(Migration... migrations) that has a start " 615d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard + "or end version equal to a start version supplied to " 616eed1cacab66988de500612cf4c6af3bcb80402efshepshapard + "fallbackToDestructiveMigrationFrom(int... " 617d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard + "startVersions). Start version: " 618d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard + version); 619d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 620d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 621d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard } 622d2658c69a5eb56c5fa7f09bd361974aa2452b320shepshapard 623059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar if (mFactory == null) { 624059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar mFactory = new FrameworkSQLiteOpenHelperFactory(); 625059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 626059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar DatabaseConfiguration configuration = 6272e8d5608ba4b3da0a05d6b6cc23d81fe10371970Yigit Boyar new DatabaseConfiguration(mContext, mName, mFactory, mMigrationContainer, 6282eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mCallbacks, mAllowMainThreadQueries, 6292eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mJournalMode.resolve(mContext), 6302eb8c31eb44ee4bc4138136b8866847b6e49e5b2Yuichi Araki mRequireMigration, mMigrationsNotRequiredFrom); 631059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX); 632059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar db.init(configuration); 633059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar return db; 634059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 635059b497bb099c867fb65e62047975ffbc41475f4Yigit Boyar } 636a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 637a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar /** 638a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * A container to hold migrations. It also allows querying its contents to find migrations 639a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * between two versions. 640a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar */ 641a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar public static class MigrationContainer { 642a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar private SparseArrayCompat<SparseArrayCompat<Migration>> mMigrations = 643a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar new SparseArrayCompat<>(); 644a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 645a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar /** 646a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * Adds the given migrations to the list of available migrations. If 2 migrations have the 647a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * same start-end versions, the latter migration overrides the previous one. 648a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * 649a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * @param migrations List of available migrations. 650a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar */ 651cceb74b52f52a57a344c02380192ce32d9565458Sergey Vasilinets public void addMigrations(@NonNull Migration... migrations) { 652a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar for (Migration migration : migrations) { 653a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar addMigration(migration); 654a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 655a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 656a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 657a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar private void addMigration(Migration migration) { 658a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar final int start = migration.startVersion; 659a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar final int end = migration.endVersion; 660a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar SparseArrayCompat<Migration> targetMap = mMigrations.get(start); 661a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (targetMap == null) { 662a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar targetMap = new SparseArrayCompat<>(); 663a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar mMigrations.put(start, targetMap); 664a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 665a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar Migration existing = targetMap.get(end); 666a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (existing != null) { 667a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar Log.w(Room.LOG_TAG, "Overriding migration " + existing + " with " + migration); 668a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 669a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar targetMap.append(end, migration); 670a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 671a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 672a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar /** 673a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * Finds the list of migrations that should be run to move from {@code start} version to 674a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * {@code end} version. 675a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * 676a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * @param start The current database version 67764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar * @param end The target database version 678a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * @return An ordered list of {@link Migration} objects that should be run to migrate 679a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar * between the given versions. If a migration path cannot be found, returns {@code null}. 680a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar */ 681e1635fb62c7bfac2b6f74fe6beacc050026f27fcSergey Vasilinets @SuppressWarnings("WeakerAccess") 682a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar @Nullable 683a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar public List<Migration> findMigrationPath(int start, int end) { 684a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (start == end) { 685a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar return Collections.emptyList(); 686a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 687a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar boolean migrateUp = end > start; 688a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar List<Migration> result = new ArrayList<>(); 689a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar return findUpMigrationPath(result, migrateUp, start, end); 690a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 691a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 692a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar private List<Migration> findUpMigrationPath(List<Migration> result, boolean upgrade, 693a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar int start, int end) { 694a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar final int searchDirection = upgrade ? -1 : 1; 695a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar while (upgrade ? start < end : start > end) { 696a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar SparseArrayCompat<Migration> targetNodes = mMigrations.get(start); 697a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (targetNodes == null) { 698a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar return null; 699a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 700a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar // keys are ordered so we can start searching from one end of them. 701a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar final int size = targetNodes.size(); 702a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar final int firstIndex; 703a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar final int lastIndex; 704a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar 705a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (upgrade) { 706a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar firstIndex = size - 1; 707a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar lastIndex = -1; 708a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } else { 709a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar firstIndex = 0; 710a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar lastIndex = size; 711a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 712a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar boolean found = false; 713a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar for (int i = firstIndex; i != lastIndex; i += searchDirection) { 714c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar final int targetVersion = targetNodes.keyAt(i); 715c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar final boolean shouldAddToPath; 716c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar if (upgrade) { 717c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar shouldAddToPath = targetVersion <= end && targetVersion > start; 718c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar } else { 719c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar shouldAddToPath = targetVersion >= end && targetVersion < start; 720c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar } 721c7d52cda65fa71ff54fca756e8abf73cdd2c7caaYigit Boyar if (shouldAddToPath) { 722a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar result.add(targetNodes.valueAt(i)); 723a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar start = targetVersion; 724a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar found = true; 725a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar break; 726a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 727a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 728a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar if (!found) { 729a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar return null; 730a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 731a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 732a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar return result; 733a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 734a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar } 735cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki 736cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki /** 737cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * Callback for {@link RoomDatabase}. 738cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki */ 739cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki public abstract static class Callback { 740cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki 741cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki /** 742cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * Called when the database is created for the first time. This is called after all the 743cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * tables are created. 744cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * 745cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * @param db The database. 746cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki */ 747cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki public void onCreate(@NonNull SupportSQLiteDatabase db) { 748cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki } 749cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki 750cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki /** 751cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * Called when the database has been opened. 752cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * 753cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki * @param db The database. 754cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki */ 755cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki public void onOpen(@NonNull SupportSQLiteDatabase db) { 756cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki } 757cf4d34906517d8ced296a96e50339c926a7dfdcdYuichi Araki } 758efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar} 759