Чтение и запись базы данных ROOM СИНХРОНИЧЕСКИ везде - PullRequest
0 голосов
/ 24 октября 2019

Я анализировал способ чтения и записи ROOM базы данных СИНХРОНИЧЕСКИ без необходимости Поставщика контента или BroadcastReceiver ,Очевидно, что доступ к базе данных должен быть асинхронным. Я нашел решение, которое делает асинхронную задачу прозрачной для программиста, используя

Callable

и

Future

интерфейсы, которые позволяют мне делать прямые вызовы к базе данных в основном потоке, а также из любой другой части приложения.

Преимущество заключается в том, что имеется почти прямой и синхронный доступ кзапрос определен в комнатном интерфейсе DAO, что подразумевает огромное преимущество перед традиционными методами;Я называю это « ЗВОНОК КЛАССА ДЛЯ КОМНАТЫ ».

Мой вопрос: какие недостатки вы видите для простых запросов?

Простой пример. Предположим, мы определили базу данных помещения с таблицей с именем « users » и в ней содержится 3 столбца: «id», «LastName»и «Имя», где вы, что вставлять, обновлять и читать вашу базу данныхинтерфейс вызывается (DB_Dao) с простыми запросами: обновите и прочитайте пользователя:

@Dao
public interface DB_Dao {

@Insert
void insert(DB_Entity data);

@Update
void update(DB_Entity data);

@Query("SELECT * FROM users ORDER BY id ASC")
List<DB_Entity> getAll();

@Query("SELECT * FROM users WHERE id IS :id")
DB_Entity getUserById(int id);

@Query("SELECT COUNT(id) FROM users")
int getCount();
}

Клиентский класс (DB_Client):

public class DB_Client {

private static DB_Client instance;
private final DB myDB;

private DB_Client(Context context) {
    myDB = Room.databaseBuilder(context, DB.class, "users").build();
}

public static synchronized DB_Client getInstance(Context context) {
    if (instance == null) {
        instance = new DB_Client(context);
    } else {
        if (!instance.myDB.isOpen()) {
            instance = new DB_Client(context);
        }
    }
    return instance;
}

инаконец ... База данных комнаты:

@Database(entities = {DB_Entity.class}, version = 1, exportSchema = false)
public abstract class DB extends RoomDatabase {
public abstract DB_Dao myDao();
}

Теперь создайте то, что я называю " CALLABLE CLASS FOR ROOM ", в котором есть все нужные вам статические методы, которые будут вызыватьсяиз любой части вашего приложения. Давайте назовем класс DB_Utilitys .class:

public class DB_Utility {

/**
 * Getter example
 * Read user
 */
public static DB_Entity getDBUser(final Context context, final int id){

    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(1);
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, workQueue);

    // Initialize the class returned variable
    DB_Entity userData = null;

    // Define what type of variable the interface will return
    Future<DB_Entity> future;

    // Execute the Callable async task using the same variable to be returned
    future = threadPoolExecutor.submit(new Callable<DB_Entity>() {

        @Override
        public DB_Entity call() {
            // TODO: here you add whatever you want to do with the database
            // In this example, the getUserById query
            DB_Dao db = DB_Client.getInstance(context).getDB().myDao();
            return db.getUserById(id);
        }
    });

    /*
    The future interface returns the result to the previously initialized variable "userData",
    has soon the room database is fetched in the CALL(). If the query takes more than the
    defined here timeout value (500ms), TimeoutException will be called.
    (You can change the value of the time out (500ms) depending of your requirements)
     */
    try {
        userData = future.get(500,TimeUnit.MILLISECONDS);
    }
    catch (ExecutionException e) {e.printStackTrace();}
    catch (InterruptedException e) {e.printStackTrace();}
    catch (TimeoutException e) {e.printStackTrace();}
    // Clear to avoid out of memory
    future.cancel(true);
    return userData;
}

/**
 * Setter example
 * Change row data
 */
public static void updateDBRow(final Context context, final DB_Entity userData){

    BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(1);
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, workQueue);

    // In this case we don't need a return value, so use Void for the Future and Callable as
    // a returning object
    Future<Void> future;
    future = threadPoolExecutor.submit(new Callable<Void>() {
        @Override
        public Void call() {
            // TODO: here you add whatever you want to do with the database
            // In this example, the update query
            DB_Dao db = DB_Client.getInstance(context).getDB().myDao();
            db.update(userData);
            // Since no return value is requiered, return null.
            return null;
        }
    });

    try {
        future.get(500,TimeUnit.MILLISECONDS);
    }
    catch (ExecutionException e) {e.printStackTrace();}
    catch (InterruptedException e) {e.printStackTrace();}
    catch (TimeoutException e) {e.printStackTrace();}
    // Clear to avoid out of memory
    future.cancel(true);
}
}

Как его использовать:

private void example(Context context) {

  // If you what to read user id 1 information call:
  DB_Entity userInfo = DB_Utility.getDBUser(context, 1);
  Log.i("mytag", " User last name: " + userInfo.getLastName());
  Log.i("mytag", "      User name: " + userInfo.getName());

  // If you want to change the name of the same user id 1 use:
  userInfo.setName("my_new_name");
  DB_Utility.updateDBRow(context, userInfo);
}
...