3

Maybe I'm missing something really simple out here but gonna ask anyways.....

I am using Xamarin forms (.NET Standard project), MVVMLight, Realm DB and ZXing Barcode Scanner.

I have a realmobject like so...

public class Participant : RealmObject
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string Email {get; set;}
    public string RegistrationCode {get; set;}

    //More properties skipped out for brevity
}

I have the corresponding viewmodel as follows:

public class ParticipantViewModel
{
    Realm RealmInstance
    public ParticipantViewModel()
    {
        RealmInstance = Realms.Realm.GetInstance();
        RefreshParticipants();
    }

    private async Task RefreshParticipants() 
    {
        //I have code here that GETS the list of Participants from an API and saves to the device.
        //I am using the above-defined RealmInstance to save to IQueryable<Participant> Participants
    }
}

All the above works fine and I have no issues with this. In the same viewmodel, I am also able to fire up the ZXing Scanner and scan a bar code representing a RegistrationCode.

This, in turn, populates the below property (also in the viewmodel) once scanned...

    private ZXing.Result result;
    public ZXing.Result Result
    {
        get { return result; }
        set { Set(() => Result, ref result, value); }
    }

and calls the below method (wired up via the ScanResultCommand) to fetch the participant bearing the scanned RegistrationCode.

    private async Task ScanResults()
    {
        if (Result != null && !String.IsNullOrWhiteSpace(Result.Text))
        {
            string regCode = Result.Text;
            await CloseScanner();
            SelectedParticipant = Participants.FirstOrDefault(p => p.RegistrationCode.Equals(regCode, StringComparison.OrdinalIgnoreCase));
            if (SelectedParticipant != null)
            {
                //Show details for the scanned Participant with regCode
            }
            else
            {
                //Display not found message
            }
        }
    }

I keep getting the below error....

System.Exception: Realm accessed from incorrect thread.

generated by the line below....

SelectedParticipant = Participants.FirstOrDefault(p => p.RegistrationCode.Equals(regCode, StringComparison.OrdinalIgnoreCase));

I'm not sure how this is an incorrect thread but any ideas on how I can get around to fetching the scanned participant either from the already populated IQueryable or from the Realm representation directly would be greatly appreciated.

Thanks

Noel
  • 373
  • 3
  • 15

1 Answers1

4

Yes, you're getting a realm instance in the constructor, and then using it from an async task (or thread). You can only access a realm from the thread in which you obtained the reference. Since you're only using a default instance, you should be able to simply obtain a local reference within the function (or thread) where you use it. Try using

    Realm LocalInstance = Realms.Realm.GetInstance();

at the top of the function and use that. You'll need to recreate the Participants query to use the same instance as its source too. This will be the case wherever you use async tasks (threads), so either change all to get hold of the default instance on entry or reduce the number of threads that access the realm.

Incidentally I'm surprised you don't get a similar access error from within RefreshParticipants() - maybe you're not actually accessing data via RealmInstance from there.

Chris Shaw
  • 1,610
  • 2
  • 10
  • 14
  • Thanks for your response. Getting a separate local instance of realm did not work as I had other bits of code using the IQueryable and I kept getting the same error. However, the first sentence in your response helped me arrive at a solution. I removed the 'async Task' signature from RefreshAttendees() as it was redundant, i.e. not calling it with await anywhere else. With this RealmInstance is now running on MainThread so I used Device.BeginInvokeOnMainThread in the ScanResults method. That got it to work. Marking your response as an answer. Cheers!! – Noel Mar 15 '19 at 10:59