Ajji
Ajji

Reputation: 3086

Calling realm from AsyncTask

Is there any way to call Realm queries from AsyncTask? I have so many queries that are doing join, So i want to call them from a separate One AsyncTask to avoid the load on UI Thread. For now i am using DefaultInstance of Realm everywhere. I get this error

Realm objects can only be accessed on the thread they where created

P.S I know Realm has its own Async for every query, but as i just mentioned i have alot of separate calls that are further doing joins and for loops.

EDIT

here's my code for an Async

    @Override
    protected Object doInBackground(Object[] params) {
        //Step 1: Find All quote_taxes
        Realm realm = Realm.getDefaultInstance();
        listTaxData = new ArrayList<TaxData>();
        try {
            RealmResults<quote_taxes> listQuoteTaxes = quote_taxes.get_from_quotes(realm, quote.getId());
            if (listQuoteTaxes != null && listQuoteTaxes.size() > 0) {
                for (quote_taxes quoteTax : listQuoteTaxes) {
                    TaxData taxData = new TaxData();
                    taxData.setTaxName(quoteTax.getTaxName());
                    taxData.setAccountNumber("" + quoteTax.getAccountNumber());
                    taxData.setTaxRate("" + quoteTax.getTaxRate() + "%");
                    double total = quote_taxes.total(realm, quoteTax);
                    showLog("Total = " + total);
                }
            }
        }catch (Exception ex)
        {

        }finally {
            realm.close();
        }
        return null;
    }

Upvotes: 3

Views: 4559

Answers (3)

EpicPandaForce
EpicPandaForce

Reputation: 81539

You just have to do what the docs say:

For AsyncTask this is a good pattern:

protected Void doInBackground(Void... params) {
    Realm realm = null;
    try {
        realm = Realm.getDefaultInstance();
        // ... Use the Realm instance ...
    } finally {
        if (realm != null) {
            realm.close();
        }
    }

    return null;
}

More importantly, you can use try-with-resources:

protected Void doInBackground(Void... params) {
    try(Realm realm = Realm.getDefaultInstance()) {
        // ... Use the Realm instance ...
    }

    return null;
}

If you are using Thread or Runnable for short-lived tasks, the follow pattern is recommended:

// Run a non-Looper thread with a Realm instance.
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Realm realm = null;
        try {
            realm = Realm.getDefaultInstance();
            // ... Use the Realm instance ...
        } finally {
            if (realm != null) {
                realm.close();
            }
        }
    }
});

thread.start();

And use a RealmChangeListener on the UI thread to be notified of successful transactions in background threads.



EDIT: Oh, you want to perform asynchronous queries.

I have so many queries that are doing join, So i want to call them from a separate One AsyncTask to avoid the load on UI Thread.

...while I truly doubt you have any "join"s considering Realm is not a relational database and the concept of joins doesn't exist in Realm; if you want asynchronous queries, you shouldn't overcomplicate your design with nonsense like AsyncTask. Just use the asynchronous query methods.

RealmResults<Something> results;
RealmChangeListener realmChangeListener = new RealmChangeListener() {
    @Override
    public void onChange(Object element) {
        if(results != null && results.isValid() && results.isLoaded()) {
            updateUI(results);
        }
    }
};

//...

results = realm.where(Something.class)./*...*/.findAllAsync(); // <-- async query
results.addChangeListener(realmChangeListener);

Upvotes: 7

Sagar Chorage
Sagar Chorage

Reputation: 1510

Realm has its Async load default functionality :-

realm.executeTransactionAsync(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                   // Use the Realm instance
                     }
            });

Above execution done on background thread, and it's gives callback when db changes like.

realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {

            }
        }, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                // success callback 
            }
        }, new Realm.Transaction.OnError() {
            @Override
            public void onError(Throwable error) {
                // error callback 
            }
        });

Upvotes: 3

Sviatoslav Melnychenko
Sviatoslav Melnychenko

Reputation: 543

I believe that you create Realm objects in doInBackground and then process results in onPostExecute? To avoid this you can use IntentService instead of AsyncTask. If you still want to use AsyncTask, you can process query results in doInBackgroundas well and then return needed data (Lists, POJOs etc.) to onPostExecute.

Upvotes: 1

Related Questions