问题
Can someone please share the implementation of a background thread with a Looper that i can pass to the subscribeOn(AndroidScheduler.from(/backgroundThreadWithLooper/)).
I need this because i am trying to implement a DBService class that runs all of its operations in the background while still getting live objects updates. So when i apply an addChangeListener, an exception is thrown:
java.lang.IllegalStateException: Your Realm is opened from a thread without a Looper. Async queries need a Handler to send results of your query
or if i use findAll() instead of findAllAsync():
java.lang.IllegalStateException: You can't register a listener from a non-Looper thread or IntentService thread.
DBService code:
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));
});
}
回答1:
HandlerThread does the job.
HandlerThread handlerThread = new HandlerThread("backgroundThread");
if (!handlerThread.isAlive())
handlerThread.start();
AndroidSchedulers.from(handlerThread.getLooper());
回答2:
this is an example of 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
}
}
回答3:
This seems to be working for me
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();
}
}
and
@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();
}
Results in
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!
So the HandlerThread Realm is able to receive automatic updates.
Copying from the Realm still results in eager evaluation of results, so it is not an efficient way of handling large data sets.
来源:https://stackoverflow.com/questions/41770875/how-to-create-a-background-thread-with-a-looper