/* * Copyright 2017, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.persistence.db; import android.arch.lifecycle.LiveData; import android.arch.lifecycle.MutableLiveData; import android.arch.persistence.room.Room; import android.content.Context; import android.os.AsyncTask; import android.support.annotation.Nullable; import android.util.Log; import java.util.concurrent.atomic.AtomicBoolean; import static com.example.android.persistence.db.AppDatabase.DATABASE_NAME; /** * Creates the {@link AppDatabase} asynchronously, exposing a LiveData object to notify of creation. */ public class DatabaseCreator { private static DatabaseCreator sInstance; private final MutableLiveData<Boolean> mIsDatabaseCreated = new MutableLiveData<>(); private AppDatabase mDb; private final AtomicBoolean mInitializing = new AtomicBoolean(true); // For Singleton instantiation private static final Object LOCK = new Object(); public synchronized static DatabaseCreator getInstance(Context context) { if (sInstance == null) { synchronized (LOCK) { if (sInstance == null) { sInstance = new DatabaseCreator(); } } } return sInstance; } /** Used to observe when the database initialization is done */ public LiveData<Boolean> isDatabaseCreated() { return mIsDatabaseCreated; } @Nullable public AppDatabase getDatabase() { return mDb; } /** * Creates or returns a previously-created database. * <p> * Although this uses an AsyncTask which currently uses a serial executor, it's thread-safe. */ public void createDb(Context context) { Log.d("DatabaseCreator", "Creating DB from " + Thread.currentThread().getName()); if (!mInitializing.compareAndSet(true, false)) { return; // Already initializing } mIsDatabaseCreated.setValue(false);// Trigger an update to show a loading screen. new AsyncTask<Context, Void, Void>() { @Override protected Void doInBackground(Context... params) { Log.d("DatabaseCreator", "Starting bg job " + Thread.currentThread().getName()); Context context = params[0].getApplicationContext(); // Reset the database to have new data on every run. context.deleteDatabase(DATABASE_NAME); // Build the database! AppDatabase db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME).build(); // Add a delay to simulate a long-running operation addDelay(); // Add some data to the database DatabaseInitUtil.initializeDb(db); Log.d("DatabaseCreator", "DB was populated in thread " + Thread.currentThread().getName()); mDb = db; return null; } @Override protected void onPostExecute(Void ignored) { // Now on the main thread, notify observers that the db is created and ready. mIsDatabaseCreated.setValue(true); } }.execute(context.getApplicationContext()); } private void addDelay() { try { Thread.sleep(4000); } catch (InterruptedException ignored) {} } }