在IntentService和AsyncTask(Android)之间使用共享代码时,域“来自错误线程的访问"错误 [英] Realm `access from incorrect thread` error when using shared code between IntentService and AsyncTask (Android)

查看:74
本文介绍了在IntentService和AsyncTask(Android)之间使用共享代码时,域“来自错误线程的访问"错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码可以下载当前"对象的JSON.但是,每当发生警报时(应用程序未运行任何UI时),IntentService都需要调用相同的代码;在应用程序运行时,也需要由AsyncTask调用.

I have some code that downloads a "Current" object's JSON. But this same code needs to be called by an IntentService whenever an alarm goes off (when the app is not running any UI), and also by an AsyncTask while the app is running.

但是,我收到一个错误消息,说Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.,但是,我不明白此堆栈跟踪是如何或为什么在另一个线程上产生的.

However, I got an error saying Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created. However, I do not understand how or why this stack trace got on a different thread.

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

I was able to get rid of the error by copying all the shared code and sticking it directly into DownloadDealService's onHandleIntent method, but it is very sloppy and I'm looking for a better solution that doesn't require duplicating code.

如何在不重复代码的情况下摆脱此错误?谢谢.

How can I get rid of this error, without duplicating code? Thanks.

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方法:

I have an AsyncTask that calls some of those Utils methods also:

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

推荐答案

[UPDATED]根据其他信息

[UPDATED] based on the additional info

RealmDatabase.getInstance()返回在主线程上创建的Realm实例.这个实例用于IntentService的线程上.导致崩溃的原因.

RealmDatabase.getInstance() was returning the Realm instance created on the main thread. And this instance was used on the IntentService's thread. Which lead to the crash.

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

Realm instances can't be used on any other thread except the one on which they were created.

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

You can't pass Realm objects between the threads. What you can do is to pass a unique identifier of the object (i.e. @PrimaryKey), and then fetch the object by its' id on another thread. Like this: realm.where(YourRealmModel.class).equalTo("primaryKeyVariable", id).findFirst().

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

For more details check out Realm's official documentation and example:

  • Using a Realm across Threads https://realm.io/docs/java/latest/#threading
  • Thread Example https://github.com/realm/realm-java/tree/master/examples/threadExample

这篇关于在IntentService和AsyncTask(Android)之间使用共享代码时,域“来自错误线程的访问"错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆