2015-05-19 5 views
8

Mam do czynienia z tym problemem na Androida:Dostęp do obszaru z nieprawidłowego wątku Android

Dostęp do obszaru z niewłaściwego wątku. Obiekty Realm mogą być dostępne tylko w wątku, w którym zostały utworzone.

chcę użyć Realm w moim RemoteViewsFactory z

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 
    } 

}

... To wywołanie nie powiodło się! Czemu ?

mogę pobrać swoje dane, takie jak to w moim klasy:

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

nazwałem mój remoteFactory tak:

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

Każdy pomysł?

+1

nie jestem zaznajomiony z RemoteViewsService, ale widocznie Twój '' 'metoda onDataSetChanged''' jest wywoływana z innego wątku niż twój' '' metody getViewAt'''. Nie jestem pewien, czy to ze względu na sposób działania RemoteViewsService lub twój kod. –

+0

Ok thxs, jak mogę to naprawić? – manua27

+0

Aby przełamać ograniczenia tej sfery, możesz odwołać się do tego posta http://stackoverflow.com/questions/26602258/how-to-achieve-the-following-in-realm-for-android/32607241#32607241. pokazuje rodzaj implementacji wrappera w celu zwolnienia aplikacji z dostępu do Realm z niepoprawnego wątku wyjątku –

Odpowiedz

2

Jeśli problem jest spowodowany przez wywołanie onDataSetChanged i getViewAt z innego wątku, można zmusić ich do korzystania z tego samego wątku, tworzenia własnych HandlerThread tak:

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

skopiowane Lock klasy z tej strony: http://tutorials.jenkov.com/java-concurrency/locks.html
Nie zapomnij o quit wątku obsługi po wykonaniu zadań.

+0

Co masz na myśli mówiąc "przestań"? – manua27

+0

Miałem na myśli tę metodę: http://developer.android.com/reference/android/os/HandlerThread.html#quit() Wątek nie kończy się, chyba że wywołasz metodę. – usp

0

Jestem oparty na RxJava, więc robię to w królestwie. Klonuję każdy przedmiot, ponieważ są one częścią głównego wątku i że zaczynają działać, gdy pracuję w innym wątku, takim ekranie głównym widgetu.

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

     for(Dog dog: mainThreadDogs){ 
      thisThreadDogs.add(ModelUtil.cloneDog(dog)); 
     }  
});