2021年4月10日星期六

Room can't build database in Android Studio I can't figure out what's wrong?

I use a Room database class on Android Studio.

I have the following entities:

User, Address, Geo, Company, Album, Photo, AlbumPhotoCrossRef (there's many-to-many relationship between Album and Photo). And I added Word too just to test.

The code for these entities are added below.

When I use only Word (comment out other classes in the entities = part, it works, I can see the table via DatabaseInspector.

But when include all entities, the database don't even open, I can't even see name of the database on DatabaseInspector.

And I get the following error:

E/AndroidRuntime: FATAL EXCEPTION: pool-2-thread-1      Process: com.example.lab8_2_room_albums, PID: 8775      java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.          at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:154)          at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:135)          at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:142)          at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:427)          at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)          at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:92)          at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:53)          at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476)          at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281)          at com.example.lab8_2_room_albums.dao.WordDao_Impl.insert(WordDao_Impl.java:57)          at com.example.lab8_2_room_albums.MainActivity.lambda$onCreate$0(MainActivity.java:59)          at com.example.lab8_2_room_albums.-$$Lambda$MainActivity$h9d6n2GFmqhE1uxj4ezb0-bRXOU.run(Unknown Source:2)          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)          at java.lang.Thread.run(Thread.java:923)  I/Process: Sending signal. PID: 8775 SIG: 9  

It refers to the line in the MainActivity where I run dao.insert(word) also where I insert a word. into database.

I did clean the project, rebuld the project too, but I still get the same error. Why? How to figure out what's wrong? And how can I fix this?

The database class is like below:

package com.example.lab8_2_room_albums.db;    import android.content.Context;    import androidx.annotation.NonNull;  import androidx.room.Database;  import androidx.room.Room;  import androidx.room.RoomDatabase;  import androidx.sqlite.db.SupportSQLiteDatabase;    import com.example.lab8_2_room_albums.dao.PhotoDAO;  import com.example.lab8_2_room_albums.dao.UserDAO;  import com.example.lab8_2_room_albums.dao.WordDao;  import com.example.lab8_2_room_albums.entities.Address;  import com.example.lab8_2_room_albums.entities.Album;  import com.example.lab8_2_room_albums.entities.AlbumPhotoCrossRef;  import com.example.lab8_2_room_albums.entities.Company;  import com.example.lab8_2_room_albums.entities.Geo;  import com.example.lab8_2_room_albums.entities.Photo;  import com.example.lab8_2_room_albums.entities.User;  import com.example.lab8_2_room_albums.entities.Word;    import java.util.concurrent.ExecutorService;  import java.util.concurrent.Executors;      @Database(entities = {Word.class, User.class, Address.class, Geo.class, Company.class, Album.class, Photo.class, AlbumPhotoCrossRef.class}, version = 1, exportSchema = true)  public abstract class UserRoomDatabase extends RoomDatabase {        //public abstract UserDAO userDAO();    //    public abstract PhotoDAO photoDAO();        public abstract WordDao wordDao();        // volatile: har sammenheng med multithreading. Sikrer at alle tråder ser samme kopi av INSTANCE.      private static volatile UserRoomDatabase INSTANCE;      private static final int NUMBER_OF_THREADS = 4;      public static final ExecutorService databaseWriteExecutor =              Executors.newFixedThreadPool(NUMBER_OF_THREADS);        public static UserRoomDatabase getDatabase(final Context context) {          if (INSTANCE == null) {              synchronized (UserRoomDatabase.class) {                  INSTANCE = Room.databaseBuilder(context.getApplicationContext(),                          UserRoomDatabase.class, "mydaaatabase")                          .addCallback(sRoomDatabaseCallback)                          .build();              }          }          return INSTANCE;      }        private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {            /**           * Called when the database is created for the first time.           * This is called after all the tables are created.           * @param db           */          @Override          public void onCreate(@NonNull SupportSQLiteDatabase db) {              super.onCreate(db);                // If you want to keep data through app restarts,              // comment out the following block              databaseWriteExecutor.execute(() -> {                  // Populate the database in the background.                    WordDao wordDao = INSTANCE.wordDao();                    //wordDao.deleteAll();                    wordDao.insert(new Word("asd"));                  wordDao.insert(new Word("adsds"));                  wordDao.getAlphabetizedWords();              });          }            @Override          public void onOpen(@NonNull SupportSQLiteDatabase db) {              super.onOpen(db);          }      };        /*      static final Migration MIGRATION_1_2 = new Migration(1, 2) {          @Override          public void migrate(SupportSQLiteDatabase database) {              database.execSQL("ALTER TABLE user "                      + " ADD COLUMN birth_year INTEGER");          }      };*/      }  

And here's the Main Activity:

package com.example.lab8_2_room_albums;    import androidx.appcompat.app.AppCompatActivity;  import androidx.lifecycle.ViewModelProvider;  import androidx.room.Room;    import android.os.Bundle;  import android.view.LayoutInflater;  import android.view.View;  import android.widget.Toast;    import com.example.lab8_2_room_albums.dao.PhotoDAO;  import com.example.lab8_2_room_albums.dao.UserDAO;  import com.example.lab8_2_room_albums.dao.WordDao;  import com.example.lab8_2_room_albums.databinding.ActivityMainBinding;  import com.example.lab8_2_room_albums.db.UserRoomDatabase;  import com.example.lab8_2_room_albums.entities.Address;  import com.example.lab8_2_room_albums.entities.Album;  import com.example.lab8_2_room_albums.entities.AlbumWithPhotos;  import com.example.lab8_2_room_albums.entities.Company;  import com.example.lab8_2_room_albums.entities.Geo;  import com.example.lab8_2_room_albums.entities.Photo;  import com.example.lab8_2_room_albums.entities.User;  import com.example.lab8_2_room_albums.entities.UserWithAlbums;  import com.example.lab8_2_room_albums.entities.UserWithCompanyWithAddressWithGeo;  import com.example.lab8_2_room_albums.entities.Word;  import com.example.lab8_2_room_albums.viewmodel.UserAlbumsViewModel;      public class MainActivity extends AppCompatActivity {        private UserAlbumsViewModel userAlbumsViewModel;        private ActivityMainBinding activityMainBinding;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);                // ViewBinding:          LayoutInflater layoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);          activityMainBinding = ActivityMainBinding.inflate(layoutInflater);          setContentView(activityMainBinding.getRoot());         //   userAlbumsViewModel = new ViewModelProvider(this).get(UserAlbumsViewModel.class);              UserRoomDatabase db = UserRoomDatabase.getDatabase(this);            WordDao dao = db.wordDao();            UserRoomDatabase.databaseWriteExecutor.execute(() -> {              // Populate the database in the background.              // If you want to start with more words, just add them.              Word word = new Word("Helloooo");              dao.insert(word);              word = new Word("Woooorld");              dao.insert(word);              dao.getAlphabetizedWords();          });      }  }  

I add some words into the words table in database. It works without any problem.

Word class:

package com.example.lab8_2_room_albums.entities;    import androidx.annotation.NonNull;  import androidx.room.ColumnInfo;  import androidx.room.Entity;  import androidx.room.PrimaryKey;    @Entity(tableName = "word_table")  public class Word {        @PrimaryKey      @NonNull      @ColumnInfo(name = "word")      private String mWord;        public Word(@NonNull String word) {this.mWord = word;}        public String getWord(){return this.mWord;}  }  

WordDAO:

package com.example.lab8_2_room_albums.dao;    import androidx.lifecycle.LiveData;  import androidx.room.Dao;  import androidx.room.Insert;  import androidx.room.OnConflictStrategy;  import androidx.room.Query;    import com.example.lab8_2_room_albums.entities.Word;    import java.util.List;    @Dao  public interface WordDao {        // allowing the insert of the same word multiple times by passing a      // conflict resolution strategy      @Insert(onConflict = OnConflictStrategy.IGNORE)      void insert(Word word);        @Query("DELETE FROM word_table")      void deleteAll();        @Query("SELECT * FROM word_table ORDER BY word ASC")      LiveData<List<Word>> getAlphabetizedWords();  }  

User class:

package com.example.lab8_2_room_albums.entities;    import androidx.annotation.NonNull;  import androidx.room.Entity;  import androidx.room.ForeignKey;  import androidx.room.PrimaryKey;    @Entity(foreignKeys = {          @ForeignKey(entity = Address.class, parentColumns = "addressId", childColumns = "fk_addressId", onDelete = ForeignKey.CASCADE),          @ForeignKey(entity = Company.class, parentColumns = "companyId", childColumns = "fk_companyId", onDelete = ForeignKey.CASCADE)  })  public class User {        @PrimaryKey(autoGenerate = true)      public long userId;        public String name;      public String username;      public String email;          public long fk_addressId;      public String phone;      public String website;      public long fk_companyId;        public User(@NonNull String name, @NonNull String username, @NonNull String email, long fk_addressId,                  @NonNull String phone, @NonNull String website, long fk_companyId) {          this.name = name;          this.username = username;          this.email = email;          this.fk_addressId = fk_addressId;          this.phone = phone;          this.website = website;          this.fk_companyId = fk_companyId;      }  }  

Address:

package com.example.lab8_2_room_albums.entities;    import androidx.annotation.NonNull;  import androidx.room.Entity;  import androidx.room.ForeignKey;  import androidx.room.PrimaryKey;    @Entity(foreignKeys = {          @ForeignKey(entity = Geo.class, parentColumns = "geoId", childColumns = "fk_geoId", onDelete = ForeignKey.CASCADE)  })  public class Address {        @PrimaryKey(autoGenerate = true)      public long addressId;        public String street;      public String suite;      public String city;      public String zipCode;        public long fk_geoId;        public Address(@NonNull String street, @NonNull String suite, @NonNull String city,                     @NonNull String zipCode, long fk_geoId) {          this.street = street;          this.suite = suite;          this.city = city;          this.zipCode = zipCode;          this.fk_geoId = fk_geoId;      }  }  

Geo:

package com.example.lab8_2_room_albums.entities;    import androidx.annotation.NonNull;  import androidx.room.Entity;  import androidx.room.PrimaryKey;    @Entity  public class Geo {        @PrimaryKey(autoGenerate = true)      public long geoId;        public double lat;      public double lng;        public Geo(@NonNull double lat, @NonNull double lng) {          this.lat = lat;          this.lng = lng;      }  }  

Company:

package com.example.lab8_2_room_albums.entities;      import androidx.annotation.NonNull;  import androidx.room.Entity;  import androidx.room.PrimaryKey;    @Entity  public class Company {      @PrimaryKey(autoGenerate = true)      public long companyId;        public String name;      public String catchPhrase;      public String bs;        public Company(@NonNull String name, @NonNull String catchPhrase, @NonNull String bs) {          this.name = name;          this.catchPhrase = catchPhrase;          this.bs = bs;      }  }  

Album:

package com.example.lab8_2_room_albums.entities;      import androidx.annotation.NonNull;  import androidx.room.Entity;  import androidx.room.ForeignKey;  import androidx.room.PrimaryKey;    @Entity(foreignKeys = {          @ForeignKey(entity = User.class, parentColumns="userId", childColumns = "fk_userId", onDelete = ForeignKey.CASCADE)  })  public class Album {        @PrimaryKey(autoGenerate = true)      public long albumId;        public long fk_userId;      public String title;        public Album(@NonNull String title, long fk_userId) {          this.title = title;          this.fk_userId = fk_userId;      }    }  

Photo:

package com.example.lab8_2_room_albums.entities;    import androidx.annotation.NonNull;  import androidx.room.Entity;  import androidx.room.PrimaryKey;    @Entity  public class Photo {        @PrimaryKey(autoGenerate = true)      public long photoId;        public String title;      public String url;      public String thumbnailUrl;        public Photo(@NonNull String title, @NonNull String url, @NonNull String thumbnailUrl) {          this.title = title;          this.url = url;          this.thumbnailUrl = thumbnailUrl;      }    }  

AlbumPhotoCrossRef:

package com.example.lab8_2_room_albums.entities;    import androidx.room.Entity;  import androidx.room.ForeignKey;    @Entity(primaryKeys = {"albumId", "photoId"},          foreignKeys = {                  @ForeignKey(entity = Album.class, parentColumns="albumId", childColumns = "albumId", onDelete = ForeignKey.CASCADE),                  @ForeignKey(entity = Photo.class, parentColumns="photoId", childColumns = "photoId", onDelete = ForeignKey.CASCADE)          }  )  public class AlbumPhotoCrossRef {      public long albumId;      public long photoId;  }  
https://stackoverflow.com/questions/67039827/room-cant-build-database-in-android-studio-i-cant-figure-out-whats-wrong April 11, 2021 at 06:29AM

没有评论:

发表评论