8

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 ?

manua27
  • 145
  • 1
  • 6
  • 1
    I am not familiar with RemoteViewsService, but apparently your ```onDataSetChanged``` method is called from another thread than your ```getViewAt``` method. I am not sure if this a because of how the RemoteViewsService work or your code. – Christian Melchior May 19 '15 at 13:05
  • Ok thxs, how can I fix it ? – manua27 May 19 '15 at 16:10
  • To break that realm limitation, you can refer this post http://stackoverflow.com/questions/26602258/how-to-achieve-the-following-in-realm-for-android/32607241#32607241. it shows wrapper kind of implementation to free your application from Realm access from incorrect thread exception – Ripal Tamboli Sep 17 '15 at 09:55

2 Answers2

2

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.

usp
  • 94
  • 3
  • What you mean concerning "quit" ? – manua27 May 21 '15 at 09:09
  • I meant this method: http://developer.android.com/reference/android/os/HandlerThread.html#quit() The thread doesn't stop unless you call the method. – usp May 21 '15 at 09:47
0

I am based on RxJava, so I do this in a realm. I clone each item because they are part of the main thread and that messes up when I am working in another thread such a widget home screen.

myRealm.where( Dog.class ).findAllAsync().subscribe( mainThreadDogs->{
       thisThreadDogs.clear();

       for( Dog dog: mainThreadDogs ){
            thisThreadDogs.add( ModelUtil.cloneDog( dog ) ); 
       }    
});
Juan Mendez
  • 2,658
  • 1
  • 27
  • 23