【问题标题】:Realm access from incorrect thread Android Retrofit2 RxJava从错误的线程 Android Retrofit2 RxJava 访问领域
【发布时间】:2017-03-22 15:39:35
【问题描述】:

我正在尝试将我的对象从 Retrofit 直接保存到 Realm 中,但总是收到错误消息:“Realm access from wrong thread”。

这是我的代码:

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

【问题讨论】:

    标签: android multithreading realm retrofit rx-java


    【解决方案1】:

    realm = Realm.getDefaultInstance(); 将返回创建对象的线程的实例。但是 Observable.map() 在 observable 发送消息的线程上被调用。

    由于 observable 来自 Retrofit,这可以是 2 个选项:

    1. 如果创建 CallAdapter 时未指定调度程序,则它将在调用 Observable.subscribe 的线程上执行。
    2. 如果 CallAdapter 是使用特定调度程序创建的,它将在该线程上执行。

    如果应用的选项与创建对象的线程不同,则会抛出“来自错误线程的领域访问”错误。

    【讨论】:

      【解决方案2】:

      Realm is thread confined,这意味着您需要确保在获得引用的同一线程上调用 Realm 对象和 realm 实例。您可能希望使用 RxAndroid 中的调度方法 observeOn() 来确保在获得 realm 实例的同一线程上调用 realm::executeTransaction()

      【讨论】:

        【解决方案3】:

        您应该在接收 API 结果的后台线程上打开 Realm 实例。

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

        虽然如果你打算返回一个托管的 RealmObject,你应该从保存的代理中映射出 ID,然后在主线程上观察并使用 ID 使用 Realm 的 UI 线程实例进行查询。

        【讨论】:

          猜你喜欢
          • 2016-09-02
          • 2017-03-13
          • 2017-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多