java - 使用 Volley 预填充房间数据库

标签 java android android-room

前言

因此,我对 Android 开发还很陌生,目前我正在开发一个应用程序,该应用程序从 REST 服务器检索数据作为 JSON 响应。该应用程序需要离线运行,因此为了实现这一目标,根据 android 的建议,我决定使用 Room Database 并遵循本教程:Room with View tutorial .

教程本身做得很好,我能够按照基本设置进行操作并根据我的需要对其进行一些调整。

问题

但是,我在使用来 self 的服务器的数据预填充 RoomDatabase 时遇到了一些麻烦。本教程使用静态数据说明了预填充方面,效果很好。但是,当我尝试修改它以使用通过 Volley 请求从服务器获取的数据时,我遇到了问题。

代码

当我尝试运行以下命令时

public abstract class AppDatabase extends RoomDatabase {

    public abstract MachineMovementDao machineMovementDao();

    private static volatile AppDatabase INSTANCE;
    private static Context ctx;

    public static AppDatabase getDatabase(final Context context) {
        ctx = context;
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                        AppDatabase.class, "local_database")
                        .addCallback(sRoomDatabaseCallback)
                        //.fallbackToDestructiveMigration()
                        .build();
                }
            }
        }
        return INSTANCE;
    }

    public static RoomDatabase.Callback sRoomDatabaseCallback =
        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 MachineMovementDao machineMovementDao;

        PopulateDbAsync(AppDatabase db) {
            machineMovementDao = db.machineMovementDao();
        }

        @Override
        protected Void doInBackground(final Void... params) {
            machineMovementDao.deleteAll();

            String url = "http://192.168.10.124:8888/movement/machine/all";

            JsonArrayRequest jsonArrayRequest = new JsonArrayRequest
                (Request.Method.GET, url, null, new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        try {
                            for (int i = 0; i < response.length(); i++) {
                                JSONObject jsonObject = response.getJSONObject(i);
                                MachineMovement movement = new MachineMovement(jsonObject);
                                machineMovementDao.insert(movement);
                            }
                        } catch (JSONException e) {
                            System.out.println(e.toString());
                        }

                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError volleyError) {
                        System.out.println(">>>>>>>>>>>>>>>>>>> > Error:" + volleyError.toString());
                    }
            });

            DataVolleyRequest.getInstance(ctx.getApplicationContext())
                .addToRequestQueue(jsonArrayRequest);

            /*
            MachineMovement movement = new MachineMovement("AMUSEMENT_MACHINE", "00003",
                "SN969NI7VCSXN", 1);
            movement.setLocationFromID(1);
            movement.setLocationToID(2);
            machineMovementDao.insert(movement);
            movement = new MachineMovement("AMUSEMENT_MACHINE", "00003",
                "SN969NI7VCSXN", 1);
            movement.setLocationFromID(2);
            movement.setLocationToID(1);
            machineMovementDao.insert(movement);
            */
            return null;
        }
    }
}

错误

出现以下错误

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sunnygroup.backoffice.tdcapp, PID: 18175
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:204)
    at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:251)
    at com.sunnygroup.backoffice.tdcapp.daos.MachineMovementDao_Impl.insert(MachineMovementDao_Impl.java:115)
    at com.sunnygroup.backoffice.tdcapp.database.AppDatabase$PopulateDbAsync$1.onResponse(AppDatabase.java:78)
    at com.sunnygroup.backoffice.tdcapp.database.AppDatabase$PopulateDbAsync$1.onResponse(AppDatabase.java:71)
    at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:90)
    at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:102)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5593)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

第 78 行是您在我的代码中看到的行

machineMovementDao.insert(movement);

如有任何帮助,我们将不胜感激

最佳答案

您可以允许空间在主线程上运行 ( https://developer.android.com/reference/androidx/room/RoomDatabase.Builder.html#allowMainThreadQueries() )

在你的情况下:

AppDatabase.class, "local_database")
                        .addCallback(sRoomDatabaseCallback)
                        .allowMainThreadQueries()
                        .build();

请注意,不建议在生产应用中这样做。

或者您可以在后台线程上运行它。您可以在 asyncTask 上运行该指令,或者考虑将 RxJava 集成到您的 Room 实现中。 Here是一个例子。

关于java - 使用 Volley 预填充房间数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54871007/

相关文章:

Android Rooms - 在字符串中搜索

java - 如果我在客户端或网页上上传 .jar 文件,如何确保其安全?

java - 如何在不知道先验拆分字符的情况下拆分字符串?

java - exe4j高dpi设置

android - 是否有必要在市场上发布应用程序以实现 android 的深度链接

java - 将 Room 持久性库与 sqlite 一起使用

android - 如何使用房间从 recyclerview 中删除一行?

Java 泛型和类型推断

android - 为 Android 中以编程方式创建的控件获取 ResourceId

java - 如何在长时间运行的操作开始之前/同时显示进度屏幕?