Search code examples
androidmultithreadingrealmretrofitrx-java

Realm access from incorrect thread Android Retrofit2 RxJava


I'm trying to save my Objects from Retrofit directly into Realm but always getting the Error:"Realm access from incorrect thread".

This is my code:

public class RestaurantRepositoryRetrofit implements IRestaurantRepository {

private RestaurantApi mApi;
private Realm realm;
private IMapper<RestaurantJson,Restaurant> mRestaurantMapper;

public RestaurantRepositoryRetrofit(IMapper<RestaurantJson, Restaurant> restaurantMapper) {
    mApi = ApiProvider.getApi().create(RestaurantApi.class);
    mRestaurantMapper = restaurantMapper;
    // Get a Realm instance for this thread
    realm = Realm.getDefaultInstance();
**}
@Override
public Observable<Restaurant> getRestaurantById(String restaurantId) {**

    return mApi.getRestaurantById(restaurantId)
            .map(new Func1<RestaurantJson, Restaurant>() {
                @Override
                public Restaurant call(RestaurantJson restaurantJson) {
                    realm.executeTransaction(new Realm.Transaction() {
                        @Override
                        public void execute(Realm realm) {

                            realm.copyToRealm(restaurantJson);
                        }
                    });
                    return mRestaurantMapper.transform(restaurantJson);
                }
            });
    }
}

Solution

  • You should open the Realm instance on the background thread that receives the results of the API.

    return mApi.getRestaurantById(restaurantId)
            .map(new Func1<RestaurantJson, Restaurant>() {
                @Override
                public Restaurant call(RestaurantJson restaurantJson) {
                    try(Realm realm = Realm.getDefaultInstance()) {
                         realm.executeTransaction(new Realm.Transaction() {
                             @Override
                             public void execute(Realm realm) {
                                 realm.copyToRealm(restaurantJson);
                             }
                         });
                         return mRestaurantMapper.transform(restaurantJson);
                    } 
                }
            });
    

    Although if you intend to return a managed RealmObject, you should map out the ID from the saved proxy and then observe on main thread and query with a UI thread instance of Realm using the ID.