【问题标题】:How to pre-populate Room Database from asset?如何从资产中预填充房间数据库?
【发布时间】:2021-04-04 19:05:37
【问题描述】:

我正在使用 SQLiteOpenHelper 类编写一个应用程序,并决定重新构建它,使用 Room 实现 MVVM 模式以获得额外的可用性。我的第一个问题是 Room 需要使用 .createFromAsset("database/data_table.db") 从 assets 文件夹加载数据库文件。它应该将它复制到设备上,然后所有进程都从那里开始,但它没有按要求复制它,开发者网站除了如何调用它之外没有指定更多内容。这里是 数据库类,每个方法的解释用于学习目的,因为我正在学习过程中。

@Database(entities = MarkerObject.class, version = 1, exportSchema = false)
public abstract class MarkerDatabase extends RoomDatabase {

    /**We create the instance so we wouldn't create multiple instances
     of the database and use the same instance throughout the application
     which is accessed through the static variable **/
    private static MarkerDatabase instance;

    /**
     *This is used to access the Dao,
     * no body is provided because Room takes care of that,
     * abstract classes don't have methods but the room generates it because of the @Dao annotation.
     */
    public abstract MarkerDao markerDao();

    /**
     * This method creates a single instance of the database,
     * then we can call this method from the outside so we have a handle to it.
     * Synchronized means that only one thread at a time can access the database
     * eliminating creating multiple instances.
     */
    public static synchronized MarkerDatabase getInstance(Context context){

        /** we want to instantiate the database
         * only if we don't have an instance, thus the if condition */
        if (instance == null) {
            instance = Room.databaseBuilder(context.getApplicationContext(),
                    MarkerDatabase.class, "locations_table")
                    .createFromAsset("database/locations_table.db")
                    .build();
        }
        return instance;
    }
} 

DAO

@Dao
public interface MarkerDao {

    @Query("SELECT * FROM locations_table")
    LiveData<List<MarkerObject>> getAllMarkers();

}

存储库

public class MarkerRepository {
  
    private MarkerDao markerDao;
    private LiveData<List<MarkerObject>> allMarkers;

    public MarkerRepository(Application application){
    
    MarkerDatabase markerDatabase = MarkerDatabase.getInstance(application);
    
    markerDao = markerDatabase.markerDao();
  
    allMarkers = markerDao.getAllMarkers();
}
public LiveData<List<MarkerObject>> getAllMarkers(){return allMarkers; }

}

视图模型

public class MarkerViewModel extends AndroidViewModel {
  
    private MarkerRepository repository;
    private LiveData<ArrayList<MarkerObject>> allMarkers;

    /**
     * We use the application as context in the constructor
     * because the ViewModel outlives the activities lifecycle.
     * To avoid memory leaks we use application as context instead of activities or views.
     */
    public MarkerViewModel(@NonNull Application application) {
        super(application);
        
        repository = new MarkerRepository(application);
        allMarkers = repository.getAllMarkers();
    }
    public LiveData<ArrayList<MarkerObject>> getAllMarkers(){
        return allMarkers;
    }
}

主活动

public class MainActivity extends AppCompatActivity {
    private MarkerViewModel markerViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView textView = findViewById(R.id.textView);

        markerViewModel = new ViewModelProvider(this).get(MarkerViewModel.class);
        markerViewModel.getAllMarkers().observe(this, new Observer<List<MarkerObject>>() {
            @Override
            public void onChanged(List<MarkerObject> markerObjects) {
                textView.setText(markerObjects.toString());
            }
        });
    }
}

现在我明白这对某些人来说可能是一个愚蠢的问题,我可能会因此受到评判,但除了互联网之外,我没有其他来源可以学习。非常感谢所有帮助。

【问题讨论】:

  • “但它没有按要求复制它”——这意味着您的数据库已经存在。如果您之前运行过应用,然后添加了此行,则需要清除应用数据或卸载应用。
  • 从另一个答案中,我得到必须首先执行查询才能创建数据库,但是正如我在提供查询后在那里指定的那样,然后我在调用 ViewModel 时遇到错误。但无论哪种方式都谢谢你。

标签: java android sqlite android-room


【解决方案1】:

您的代码很好,应该可以正常工作。

需要检查的几件事:

  • 首先:确保location_table.db文件存在于app\src\main\assets\database目录下

它应该将它复制到设备上,然后所有进程都从那里开始,但它没有按要求复制它,开发者网站除了如何调用它没有指定更多

  • 第二createFromAsset() & createFromFile 永远不会被执行并创建数据库文件,除非您对数据库执行一些事务或查询。更多信息请查看the accepted answer here

更新

错误是java.lang.RuntimeException: Cannot create an instance of class com.example.roomtextfirst.MarkerViewModeL

首先,我看不出您的新共享代码有任何问题。 我只需要您确保您在模块 gradle 文件中具有以下依赖项:

implementation 'androidx.fragment:fragment:1.2.2'
implementation 'androidx.lifecycle:lifecycle-process:2.2.0'
implementation 'androidx.lifecycle:lifecycle-service:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0'

而不是那些已弃用的:

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc01'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0-rc01'

还要感谢answers here 也可以为您提供指导。

【讨论】:

  • 现在资产文件夹已按要求创建,但我没有从 DAO 调用任何方法,因为我不知道它只会创建一次查询,现在我已经添加了调用获取从存储库到 ViewModel 到 MainActivity 的所有标记,然后我在 markerViewModel = new ViewModelProvider(this).get(MarkerViewModel.class); 上收到一个错误,错误是 ``` java.lang.RuntimeException: Cannot create an instance of class com.example.roomtextfirst.MarkerViewModel ```,所以至少更进一步。
  • @EdwardAarma 请用 ViewModel 类更新问题,dao,如果你有一个 Repository .. 这样我们就可以有一个完整的画面
  • @EdwardAarma 感谢分享.. 请检查更新的答案.. 此错误可能有多种原因,因此您可以检查答案中的附加链接。
  • welcome :) .. MarkerObject 是你的数据/pojo 类 .. 在 java 对象类有 toString() 方法.. 如果你想将一个对象转换为字符串,然后覆盖 @987654333 @ 可以返回一些字段值以放入 TextView 或作为日志打印给用户
  • 也谢谢你的最后一点,它消除了我对对象的轻微误解。
猜你喜欢
  • 2020-04-12
  • 1970-01-01
  • 1970-01-01
  • 2020-10-22
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多