Ajji Ajji - 8 days ago 7
Android Question

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

Answer

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

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);