在 IntentService 和 AsyncTask 之间使用共享代码时,领域“从不正确的线程访问”错误 (Android)

Realm `access from incorrect thread` error when using shared code between IntentService and AsyncTask (Android)

我有一些代码可以下载 "Current" 对象的 JSON。但是每当警报响起时(当应用程序不是 运行 任何 UI 时),以及当应用程序处于 运行 时,AsyncTask 也需要调用相同的代码。

但是,我收到一条错误消息 Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created. 但是,我不明白此堆栈跟踪如何或为何出现在不同的线程上。

我能够通过复制所有共享代码并将其直接粘贴到 DownloadDealService 的 onHandleIntent 方法中来消除错误,但它非常草率,我正在寻找一个更好的解决方案不需要复制代码。

如何在不复制代码的情况下摆脱这个错误?谢谢。

public class DownloadDealService extends IntentService
{
    ...
    @Override
    protected void onHandleIntent(Intent intent)
    {
        Current todaysCurrent = Utils.downloadTodaysCurrent(); //<--- included for background info
        String dateString = Utils.getMehHeadquartersDate(); //(omitted)
        Utils.onDownloadCurrentCompleteWithAlarm(todaysCurrent, dateString); //<------ calling this...
    }
}

public class Utils
{
    // ...other methods ommitted...

    //This method is not in the stack trace, but I included it for background information.
    public static Current downloadTodaysCurrent()
    {
        //Set up Gson object... (omitted)
        //Set up RestAdapter object... (omitted)
        //Set up MehService class... (omitted)

        //Download "Current" object from the internet.
        Current current = mehService.current(MehService.API_KEY);
        return current;
    }

    //Included for background info- this method is not in the stack trace.
    public static void onDownloadCurrentComplete(Current result, String dateString)
    {
        if(result.getVideo() == null)
        {
            Log.e("HomePage", "Current was not added on TaskComplete");
            return;
        }
        remainder(result, dateString);
    }

    public static void onDownloadCurrentCompleteWithAlarm(Current result, String dateString)
    {
        //Set alarm if download failed and exit this function... (omitted)

        remainder(result, dateString);//<------ calling this...
        Utils.sendMehNewDealNotification(App.getContext());
    }

    public static void remainder(Current result, String dateString)
    {
        Realm realm = RealmDatabase.getInstance();

        //Add "Current" to Realm
        Current current = Utils.addCurrentToRealm(result, realm); //<------ calling this...
    }

    public static Current addCurrentToRealm(Current current, Realm realm)
    {
        realm.beginTransaction(); //<---- Error is here
        Current result = realm.copyToRealmOrUpdate(current);
        realm.commitTransaction();
        return result;
    }
}

堆栈跟踪:

E/AndroidRuntime: FATAL EXCEPTION: IntentService[DownloadDealService]
Process: com.example.lexi.meh, PID: 13738
java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
    at io.realm.Realm.checkIfValid(Realm.java:191)
    at io.realm.Realm.beginTransaction(Realm.java:1449)
    at com.example.lexi.meh.Utils.Utils.addCurrentToRealm(Utils.java:324)
    at com.example.lexi.meh.Utils.Utils.remainder(Utils.java:644)
    at com.example.lexi.meh.Utils.Utils.onDownloadCurrentCompleteWithAlarm(Utils.java:635)
    at com.example.lexi.meh.Home.DownloadDealService.onHandleIntent(DownloadDealService.java:42)
    at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.os.HandlerThread.run(HandlerThread.java:61)

我有一个 AsyncTask 也调用其中一些 Utils 方法:

public class DownloadAsyncTask extends AsyncTask<Void, Integer, Current>
{
    // ... (more methods ommitted)...

    protected Current doInBackground(Void... voids)
    {
        return Utils.downloadTodaysCurrent(); //<---- shared Utils method
    }
}

//Async class's callback in main activity:
public class HomePage extends AppCompatActivity implements DownloadAsyncTaskCallback, DownloadAsyncTaskGistCallback<Current, String>
{
    // ... (more methods ommitted)...

    public void onTaskComplete(Current result, String dateString)
    {
        Utils.onDownloadCurrentComplete(result, dateString);
    }
}

问题是你从不同的线程调用方法,你必须使用同一个线程,创建你自己的 HandlerThread。

[已更新] 基于附加信息

RealmDatabase.getInstance() 返回在主线程上创建的 Realm 实例。而这个实例是在 IntentService 的线程上使用的。导致崩溃。

Realm 实例不能在创建它们的线程之外的任何其他线程上使用。


您不能在线程之间传递 Realm 对象。您可以做的是传递对象的唯一标识符(即@PrimaryKey),然后在另一个线程上通过其“id”获取对象。像这样:realm.where(YourRealmModel.class).equalTo("primaryKeyVariable", id).findFirst().

有关更多详细信息,请查看 Realm 的官方文档和示例:

如果您在 IntentService 中使用 Realm,您将使用新的 Realm。例如

Realm.getInstance(RealmConfiguration config) 

我用的是 IntentService 中的 Realm

@Override
protected void onHandleIntent(Intent intent) {
    Realm realm = Realm.getDefaultInstance();
    ...
    realm.close(); // important on background thread
}