简体   繁体   中英

Pre-populate Room Database with Volley

Preface

So, I am pretty new to android development and at the moment I am developing an application that retrieves data from a REST server as a JSON response. The application needs to be functional offline, so in an effort to accomplish this, based on android recommendation, I decided to use Room Database and followed this tutorial: Room with View tutorial .

The tutorial itself was well done, and I was able to follow the basic set up and tailor it a bit to my needs.

Problem

I am however having a bit of trouble pre-populating the RoomDatabase with data from my server. The tutorial illustrated the pre-populating aspect by using static data, and this works fine. However, when I try to modify that to use the data fetched from the server, via the Volley request, is where I am running into problems.

Code

When I attempt to run the following

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;
        }
    }
}

Error

I get the following error

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)

line 78 is the line in my code where you see

machineMovementDao.insert(movement);

Any assistance would be greatly appreciated

You can either allow room to run on the main thread ( https://developer.android.com/reference/androidx/room/RoomDatabase.Builder.html#allowMainThreadQueries() )

In your case:

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

Note that this is not recommended on production apps.

Or you can run that on a background thread. You can either run that instruction on an asyncTask or look into integrating RxJava into your Room implementation. Here is an example.

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