Jedd Axell
Jedd Axell

Reputation: 5

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

experiencing an error when trying to make new objects through a button with a relationship (one-to-many) from another page, using realm with recycler view to connect multiple to tasks to one note(the list of tasks)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.task_activity);

    final Realm mrealm = Realm.getDefaultInstance();
    RealmResults<tItem> results = mrealm.where(tItem.class).findAll();

    final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);


    final tData data = new tData(); 
    fbtn1 = (FloatingActionButton) findViewById(R.id.fbtn1);
    recView = (RecyclerView)findViewById(R.id.task_list);
    recView.setLayoutManager(layoutManager);


    adapter = new tAdapter(results,this);
    recView.setAdapter(adapter);
    adapter.setIconClickCallback(this);



    fbtn1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {


            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mrealm.executeTransactionAsync(new Realm.Transaction() {
                        @Override
                        public void execute(Realm realm) {
                            final RealmResults<tItem> item2 = realm.where(tItem.class).findAll();

                            tItem item = mrealm.createObject(tItem.class);
                            UUID.randomUUID()
                                    .toString();
                            taskData.add(item);
                            item.setTasks("to do list 1");
                            mrealm.copyToRealm(item);
                        }
                    });
                }
            });


            adapter.notifyDataSetChanged();
            RealmResults<tItem> tItem = mrealm.where(tItem.class).findAll();
            Log.d("john", "new task ");
            Log.d("", "path: " + mrealm.getPath());
        }
    });
}

the error points to this part of the code

tItem item = mrealm.createObject(tItem.class);

Upvotes: 0

Views: 1141

Answers (4)

mcfly
mcfly

Reputation: 834

The best idea is to make a copy on you thread if you want to have it on this one.

Also, you should try to make request in a DAO or REPOSITORY pattern. I made a repository pattern like this :

public Observable<List<T>> query(final Specification spec) {
    return Observable.create(new ObservableOnSubscribe<List<T>>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<List<T>> emitter) throws Exception {
            Log.d(TAG, "OnSubscribe ::  Thread id :"+Thread.currentThread().getId() + " name : "+Thread.currentThread().getName());
            Realm realm = Realm.getDefaultInstance();
            final RealmSpecification realmSpecification = (RealmSpecification) spec;
            RealmResults<T> res = realmSpecification.toRealmResults(realm);
            List<T> resList = realm.copyFromRealm(res);
            realm.close();
            if(res != null)
                emitter.onNext(resList);
            emitter.onComplete();
        }
    });
}

like that i can query my base from a thread to the main thread. All my queries uses these functions.

Upvotes: 0

EpicPandaForce
EpicPandaForce

Reputation: 81539

Your code is supposed to look like this:

Realm realm;

RealmResults<tItem> results;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.task_activity);

    realm = Realm.getDefaultInstance();
    results = realm.where(tItem.class).findAll();

    final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    fbtn1 = (FloatingActionButton) findViewById(R.id.fbtn1);
    recView = (RecyclerView)findViewById(R.id.task_list);
    recView.setLayoutManager(layoutManager);

    adapter = new tAdapter(results,this); // tAdapter extends RealmRecyclerViewAdapter
    recView.setAdapter(adapter);
    adapter.setIconClickCallback(this);

    fbtn1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            fbtn1Clicked();
        }
    });
}

private void fbtn1Clicked() {
    realm.executeTransactionAsync(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            final RealmResults<tItem> items = realm.where(tItem.class).findAll();
            tItem item = realm.createObject(tItem.class, UUID.randomUUID().toString();
            item.setTasks("to do list 1");
        }
    });
}

@Override
public void onDestroy() {
    super.onDestroy();
    if(realm != null) {
        realm.close();
        realm = null;
    }
}

But your original error is that instead of

tItem item = mrealm.createObject(tItem.class);

you should have

tItem item = realm.createObject(tItem.class); // <-- background thread realm

Upvotes: 0

Sathyajith
Sathyajith

Reputation: 4024

Try creating tItem class using the realm instance instead of mRealm instance since that is the realm instance created for the async transaction

tItem item = realm.createObject(tItem.class);

Upvotes: 0

Alex Shutov
Alex Shutov

Reputation: 3282

Realm instance is thread - confined - you cannot make queries from another thread. This error occures, because you make query on a main thred and then attempt to use that query in async transaction, which will be executed on another thread:

final RealmResults<tItem> item2 = realm.where(tItem.class).findAll();

Upvotes: 0

Related Questions