manua27 manua27 - 5 months ago 81
Android Question

Realm access from incorrect thread Android

I am dealing with this issue on Android :

Realm access from incorrect thread. Realm objects can only be accessed on the thread they where created.

I want to use Realm in my RemoteViewsFactory with

public class RemoteViewsX implements RemoteViewsFactory {

public RemoteViews getViewAt(int paramInt) {
if (this.results != null && this.results.size() != 0 && this.results.get(paramInt) != null) {
//FAILED HERE
}


}

...
This call failed! Why ?

I fetch my data like this in my class:

public void onDataSetChanged() {
Realm realm = Realm.getInstance(RemoteViewsX.this.ctx);
this.results = realm.where(Model.class).findAll();
}


I called my remoteFactory like this :

public class ScrollWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new RemoteViewsX (getApplicationContext());
}
}


Any idea ?

usp usp
Answer Source

If the problem is caused by calling onDataSetChanged and getViewAt from another thread, you can force them to use the same thread, creating your own HandlerThread like this:

public class Lock {
    private boolean isLocked;

    public synchronized void lock() throws InterruptedException {
        isLocked = true;
        while (isLocked) {
            wait();
        }
    }

    public synchronized void unlock() {
        isLocked = false;
        notify();
    }
}

public class MyHandlerThread extends HandlerThread {
    private Handler mHandler;

    public MyHandlerThread() {
        super("MY_HANDLER_THREAD");
        start();
        mHandler = new Handler(getLooper());
    }

    public Handler getHandler() {
        return mHandler;
    }
}

public class RemoteViewsX implements RemoteViewsFactory {
    private MyHandlerThread mHandlerThread;
    ...
}

public void onDataSetChanged() {
    Lock lock = new Lock();
    mHandlerThread.getHandler().post(new Runnable() {
        @Override
        public void run() {
            Realm realm = Realm.getInstance(ctx);
            results = realm.where(Model.class).findAll();
            lock.unlock();
        }
    });
    lock.lock();
}

public RemoteViews getViewAt(int paramInt) {
    Lock lock = new Lock();
    final RemoteViews[] result = {null};
    mHandlerThread.getHandler().post(new Runnable() {
        @Override
        public void run() {
            // You can safely access results here.
            result[0] = new RemoteViews();
            lock.unlock();
        }
    });
    lock.lock();
    return result[0];
}

I copied Lock class from this page: http://tutorials.jenkov.com/java-concurrency/locks.html
Do not forget to quit the handler thread when your tasks are done.