如何使用looper创建后台线程

时间:2017-01-20 19:18:16

标签: android multithreading realm

有人可以与Looper共享后台线程的实现,我可以将其传递给subscribeOn(AndroidScheduler.from(/ backgroundThreadWithLooper /))。

我需要这个,因为我正在尝试实现一个DBService类,它在后台运行所有操作,同时仍然获得实时对象更新。因此,当我应用addChangeListener时,会抛出异常:

java.lang.IllegalStateException: Your Realm is opened from a thread without a Looper. Async queries need a Handler to send results of your query

或者如果我使用findAll()而不是findAllAsync():

java.lang.IllegalStateException: You can't register a listener from a non-Looper thread or IntentService thread.

DBService代码:

public Observable<List> getAll(Class clazz) {
    return Observable.defer(() -> {
        Realm realm = Realm.getDefaultInstance();
        return realm.where(clazz).findAll().asObservable()
                .map(o -> realm.copyFromRealm((RealmResults) o))
                .doOnUnsubscribe(() -> closeRealm(realm))
                .doOnTerminate(() -> closeRealm(realm));
    });
}

3 个答案:

答案 0 :(得分:6)

HandlerThread完成这项工作。

HandlerThread handlerThread = new HandlerThread("backgroundThread");
if (!handlerThread.isAlive())
    handlerThread.start();
AndroidSchedulers.from(handlerThread.getLooper());

答案 1 :(得分:0)

这是Thread with Looper的一个例子:

public class GameLoop extends Thread {

@Override
public void run() {
    super.run();
    Looper.prepare(); // at first write this line of code
    //do something
    Looper.loop(); //and at the end write this line
}

}

答案 2 :(得分:0)

这似乎对我有用

public class MainScopeListener
        extends Fragment {
    Realm realm;

    HandlerThread handlerThread;

    Scheduler looperScheduler;

    Observable<Realm> realmObservable;

    Subscription realmSubscription;

    Handler handler = new Handler(Looper.getMainLooper());

    public MainScopeListener() {
        setRetainInstance(true);
        realm = Realm.getDefaultInstance();
        Injector.INSTANCE.initializeComponent(realm);
        handlerThread = new HandlerThread("REALM_LOOPER") {
            @Override
            protected void onLooperPrepared() {
                super.onLooperPrepared();
                Log.i(getName(), "ON LOOPER PREPARED");
                handler.post(() -> {
                    looperScheduler = AndroidSchedulers.from(handlerThread.getLooper());
                    realmObservable = Observable.create(new Observable.OnSubscribe<Realm>() {
                        @Override
                        public void call(Subscriber<? super Realm> subscriber) {
                            final Realm observableRealm = Realm.getDefaultInstance();
                            observableRealm.setAutoRefresh(true);
                            final RealmChangeListener<Realm> listener = realm1 -> {
                                if (!subscriber.isUnsubscribed()) {
                                    subscriber.onNext(observableRealm);
                                }
                            };
                            subscriber.add(Subscriptions.create(() -> {
                                observableRealm.removeChangeListener(listener);
                                observableRealm.setAutoRefresh(false);
                                observableRealm.close();
                            }));
                            observableRealm.addChangeListener(listener);

                            // Immediately call onNext with the current value, as due to Realm's auto-update, it will be the latest
                            // value.
                            subscriber.onNext(observableRealm);
                        }
                    });
                    realmSubscription = realmObservable.unsubscribeOn(looperScheduler).subscribeOn(looperScheduler).subscribe(realm12 -> {
                        Log.i("REALM SUBSCRIPTION", "An event occurred on background thread!");
                    });
                });
            }
        };
        handlerThread.start();
    }

    public void configureRealmHolder(MainActivity.RealmHolder realmHolder) {
        realmHolder.realm = this.realm;
    }

    @Override
    public void onDestroy() {
        if(realmSubscription != null && !realmSubscription.isUnsubscribed() ) {
            realmSubscription.unsubscribe();
        }
        handlerThread.quit();
        realm.close();
        super.onDestroy();
    }
}

@SuppressWarnings("NewApi")
private Subscription writePeriodic() {
    return Observable.interval(2000, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) //
            .takeWhile(aLong -> counter < DogNames.values().length) //
            .observeOn(Schedulers.io())
            .doOnNext(aLong -> {
                try(Realm bgRealm = Realm.getDefaultInstance()) {
                    bgRealm.executeTransaction(realm1 -> {
                        long currentIndex = realm1.where(Dog.class).max(Dog.Fields.ID.getField()).longValue();
                        Dog dog = new Dog();
                        dog.setId(currentIndex + 1);
                        dog.setName(DogNames.values()[((Long) dog.getId()).intValue() % DogNames.values().length].name());
                        dog = realm1.copyToRealmOrUpdate(dog);
                        Log.i(TAG, "Realm write successful [" + counter + "] :: [" + dog.getName() + "].");
                        counter++;
                    });
                }
            }).subscribe();
}

结果

01-21 00:58:51.672 2094-2127/com.zhuinden.rxrealm I/DogView: Realm write successful [1] :: [Munch].
01-21 00:58:51.672 2094-2115/com.zhuinden.rxrealm I/REALM SUBSCRIPTION: An event occurred on background thread!

因此HandlerThread Realm能够接收自动更新。

从Realm复制仍然会导致对结果的热切评估,因此它不是处理大型数据集的有效方法。