Search code examples
androiddatabaseasynchronousrealmlooper

Android error with realm, trying to use async. Says it's opened from a thread with no looper


I get the following error at this code: "Your Realm is opened from a thread without a Looper. Async queries need a Handler to send results of your query" at this line:

"RealmResults<UserVehicle> completed = realm.where(UserVehicle.class).equalTo("id", userVehicleID).findAllAsync();"

I tried setting the realm.executeTransaction inside a Handler(Looper.getMain()) but with no luck. What am I doing wrong?

PSVehicleService.getInstance(PSVehicleDetailsActivity.this).fetchVehicleTrips(userVehicle, fiveWeeksBeforeDate, lastTripDate, userID, new JsonCallback() {
            @Override
            public void onResponse(final JSONObject jsonObject, VolleyError error) {
                if(jsonObject != null) {
                    Log.i("","testVehicles maybeFetchData 11");
                    realm.executeTransaction(new Realm.Transaction() {
                        @Override
                        public void execute(Realm realm) {
                            try {
                                ObjectMapper mapper = new ObjectMapper();
                                final List<Trip> trips = mapper.readValue(jsonObject.getJSONArray("trips").toString(), new TypeReference<List<Trip>>() {
                                });
                                Log.i("","testVehicles maybeFetchData 12");
                                RealmResults<UserVehicle> completed = realm.where(UserVehicle.class).equalTo("id", userVehicleID).findAllAsync();
                                UserVehicle userVehicle = null;
                                if(completed.size() > 0){
                                    userVehicle = completed.get(0);
                                }
                                if(userVehicle != null) {
                                    Log.i("", "testVehicles maybeFetchData 13");
                                    userVehicle.getTrips().clear();
                                    Log.i("", "testVehicles maybeFetchData 14");
                                    userVehicle.getTrips().addAll(trips);
                                    Log.i("", "testVehicles maybeFetchData 15");
                                    realm.copyToRealmOrUpdate(userVehicle);
                                    Log.i("", "testVehicles maybeFetchData 16");
                                }else{
                                    Log.i("", "testVehicles maybeFetchData 16 NULLLLLLLL");
                                }
                            } catch (Exception e) {
                                Log.i("", "fetchTripsSinceWeeksInPast fetchVehicleTrips2 error" + e.getMessage());
                                Utils.appendLog("ERROR fetchVehicleTrips is:" + e.getMessage(), true);
                            }
                        }
                    }, new Realm.Transaction.Callback() {
                        @Override
                        public void onSuccess() {
                            Log.i("","testVehicles maybeFetchData 17");
                            setPager();
                            Log.i("","testVehicles maybeFetchData 18");
                        }

                        @Override
                        public void onError(Exception e) {
                            Log.i("","testVehicles maybeFetchData 18 ERROR:" + e.getMessage());
                        }
                    });
                }
            }
        });

Solution

  • The problem is you are using async queries in an async transaction -- which is not necessary at all.

    When calling realm.executeTransaction(Realm.Transaction, Realm.Transaction.Callback), the code block in the transaction will run in an worker thread which doesn't have an looper and doesn't need a looper.

    But for async queries, you need a looper to make sure the query result can be delivered back on Android.

    So, to fix your problem, just simply use sync query instead, just let it run in the transaction's worker thread. as:

    RealmResults<UserVehicle> completed = realm.where(UserVehicle.class).equalTo("id", userVehicleID).findAll();