简体   繁体   中英

Android java, Dao interface in the database class seems to be weird

I was recently learning Room Database but this code seems too weird. I tried to understand this line of code but maybe my google search skill isn't that good. Can you explain this?

public abstract NoDoDao noDoDao();

The thing I don't understand, how Interface which is 'NoDoDa' here, can be called as if it were 'method' or 'function'? This is my first time seeing this syntax. And why is there also 'Abstract keyword'?

package com.paige.room.data;

import android.content.Context;
import android.os.AsyncTask;

import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.sqlite.db.SupportSQLiteDatabase;

import com.paige.room.model.NoDo;

@Database(entities = {NoDo.class}, version = 1)
public abstract class NoDoRoomDatabase extends RoomDatabase {

    //Don't want to create a lot of instances, singleton
    //volatile means "don't store in the cache"
    private static volatile NoDoRoomDatabase INSTANCE;
    public abstract NoDoDao noDoDao();

    public static NoDoRoomDatabase getDatabase(final Context context){
        if(INSTANCE == null){
            //synchronized keyword, for UI Thread, force it to work as it is supposed to do
            synchronized (NoDoRoomDatabase.class){
                if(INSTANCE == null){
                    //create our db
                    INSTANCE = Room.databaseBuilder(
                            context,
                            NoDoRoomDatabase.class,
                            "nodo_database")
                            .addCallback(roomDatabaseCallBack)
                            .build();
                }
            }
        }
        return INSTANCE;
    }

    //callback
    private static RoomDatabase.Callback roomDatabaseCallBack =
            new RoomDatabase.Callback(){
                @Override
                public void onOpen(@NonNull SupportSQLiteDatabase db) {
                    super.onOpen(db);
                    new PopulateDBAsync(INSTANCE).execute();
                }
            };


    private static class PopulateDBAsync extends AsyncTask<Void, Void, Void> {
        private final NoDoDao noDoDao;

        PopulateDBAsync(NoDoRoomDatabase db) {
            this.noDoDao = db.noDoDao();
        }

        @Override
        protected Void doInBackground(Void... voids) {
//            noDoDao.deleteAll(); //removes all items from our table
//            //for testing
//            NoDo noDo = new NoDo("Buy a new Ferrari");
//            noDoDao.insert(noDo);
//
//            noDo = new NoDo("Buy a Big House");
//            noDoDao.insert(noDo);

            return null;
        }
    }

}

This is my entire code

NoDoDao is an abstract class, it cannot be instantiated (constructed) but the class can be used. Which is what is happening here.

What you may not be aware of is that Room generates code and it is these abstractions that allow the underlying code to be implemented on your behalf.

Say for example that you Entity class NoDO is :-

@Entity
public class NoDo {

    @PrimaryKey
    Long id;
}

And your Dao class NoDoDao is :-

@Dao
public abstract class NoDoDao {

    @Query("SELECT * FROM nodo")
    abstract List<NoDo> getnothing();
}

And you compile (F9) then you get :-

在此处输入图片说明

Looking at NoDoDao_Impl then you get :-

public final class NoDoDao_Impl extends NoDoDao {
  private final RoomDatabase __db;

  public NoDoDao_Impl(RoomDatabase __db) {
    this.__db = __db;
  }

  @Override
  List<NoDo> getnothing() {
    final String _sql = "SELECT * FROM nodo";
    final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
    __db.assertNotSuspendingTransaction();
    final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
    try {
      final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
      final List<NoDo> _result = new ArrayList<NoDo>(_cursor.getCount());
      while(_cursor.moveToNext()) {
        final NoDo _item;
        _item = new NoDo();
        if (_cursor.isNull(_cursorIndexOfId)) {
          _item.id = null;
        } else {
          _item.id = _cursor.getLong(_cursorIndexOfId);
        }
        _result.add(_item);
      }
      return _result;
    } finally {
      _cursor.close();
      _statement.release();
    }
  }
} 

That is the real getNothing code has been generated by the annotation processor.

As important is that the NoDoRoomDatabase_Impl is :-

public final class NoDoRoomDatabase_Impl extends NoDoRoomDatabase {
  private volatile NoDoDao _noDoDao;

  @Override
  protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
    final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) {
      @Override
      public void createAllTables(SupportSQLiteDatabase _db) {
        _db.execSQL("CREATE TABLE IF NOT EXISTS `NoDo` (`id` INTEGER, PRIMARY KEY(`id`))");
        _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
        _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1fdde93d9c60610ae88bf0c74771844a')");
      }

      @Override
      public void dropAllTables(SupportSQLiteDatabase _db) {
        _db.execSQL("DROP TABLE IF EXISTS `NoDo`");
        if (mCallbacks != null) {
          for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
            mCallbacks.get(_i).onDestructiveMigration(_db);
          }
        }
      }

      @Override
      protected void onCreate(SupportSQLiteDatabase _db) {
        if (mCallbacks != null) {
          for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
            mCallbacks.get(_i).onCreate(_db);
          }
        }
      }

      @Override
      public void onOpen(SupportSQLiteDatabase _db) {
        mDatabase = _db;
        internalInitInvalidationTracker(_db);
        if (mCallbacks != null) {
          for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
            mCallbacks.get(_i).onOpen(_db);
          }
        }
      }

      @Override
      public void onPreMigrate(SupportSQLiteDatabase _db) {
        DBUtil.dropFtsSyncTriggers(_db);
      }

      @Override
      public void onPostMigrate(SupportSQLiteDatabase _db) {
      }

      @Override
      protected RoomOpenHelper.ValidationResult onValidateSchema(SupportSQLiteDatabase _db) {
        final HashMap<String, TableInfo.Column> _columnsNoDo = new HashMap<String, TableInfo.Column>(1);
        _columnsNoDo.put("id", new TableInfo.Column("id", "INTEGER", false, 1, null, TableInfo.CREATED_FROM_ENTITY));
        final HashSet<TableInfo.ForeignKey> _foreignKeysNoDo = new HashSet<TableInfo.ForeignKey>(0);
        final HashSet<TableInfo.Index> _indicesNoDo = new HashSet<TableInfo.Index>(0);
        final TableInfo _infoNoDo = new TableInfo("NoDo", _columnsNoDo, _foreignKeysNoDo, _indicesNoDo);
        final TableInfo _existingNoDo = TableInfo.read(_db, "NoDo");
        if (! _infoNoDo.equals(_existingNoDo)) {
          return new RoomOpenHelper.ValidationResult(false, "NoDo(a.so59478461.NoDo).\n"
                  + " Expected:\n" + _infoNoDo + "\n"
                  + " Found:\n" + _existingNoDo);
        }
        return new RoomOpenHelper.ValidationResult(true, null);
      }
    }, "1fdde93d9c60610ae88bf0c74771844a", "1d145662ebde2538a8da3217996c0550");
    final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
        .name(configuration.name)
        .callback(_openCallback)
        .build();
    final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);
    return _helper;
  }

  @Override
  protected InvalidationTracker createInvalidationTracker() {
    final HashMap<String, String> _shadowTablesMap = new HashMap<String, String>(0);
    HashMap<String, Set<String>> _viewTables = new HashMap<String, Set<String>>(0);
    return new InvalidationTracker(this, _shadowTablesMap, _viewTables, "NoDo");
  }

  @Override
  public void clearAllTables() {
    super.assertNotMainThread();
    final SupportSQLiteDatabase _db = super.getOpenHelper().getWritableDatabase();
    try {
      super.beginTransaction();
      _db.execSQL("DELETE FROM `NoDo`");
      super.setTransactionSuccessful();
    } finally {
      super.endTransaction();
      _db.query("PRAGMA wal_checkpoint(FULL)").close();
      if (!_db.inTransaction()) {
        _db.execSQL("VACUUM");
      }
    }
  }

  @Override
  public NoDoDao noDoDao() {
    if (_noDoDao != null) {
      return _noDoDao;
    } else {
      synchronized(this) {
        if(_noDoDao == null) {
          _noDoDao = new NoDoDao_Impl(this);
        }
        return _noDoDao;
      }
    }
  }
}

See how NoDoDao has been overridden to basically be NoDoDao_Impl

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM