Ошибка доступа Realm от неправильной нити при использовании общего кода между IntentService и AsyncTask (Android)

У меня есть код, который загружает JSON «Текущий» объект. Но этот же код должен вызываться IntentService всякий раз, когда будильник отключается (когда приложение не запускает какой-либо пользовательский интерфейс), а также AsyncTask во время работы приложения.

Тем не менее, я получил сообщение об ошибке Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created. Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created. Однако я не понимаю, как и почему эта трассировка стека попала в другой поток.

Я смог избавиться от ошибки, скопировав весь общий код и onHandleIntent его непосредственно к методу 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); } } 

Solutions Collecting From Web of "Ошибка доступа Realm от неправильной нити при использовании общего кода между IntentService и AsyncTask (Android)"

[ОБНОВЛЕНО] на основе дополнительной информации

RealmDatabase.getInstance () возвращал экземпляр Realm, созданный в основном потоке. И этот экземпляр использовался в потоке IntentService. Это привело к катастрофе.

Экземпляры Realm нельзя использовать ни в одном другом потоке, кроме того, на котором они были созданы.


Вы не можете передавать объекты Realm между потоками. Что вы можете сделать, так это передать уникальный идентификатор объекта (т. Е. @PrimaryKey), а затем извлечь объект по его «id в другой поток». Например: realm.where (YourRealmModel.class) .equalTo ("primaryKeyVariable", id) .findFirst ().

Для получения дополнительной информации ознакомьтесь с официальной документацией и примером Realm:

Проблема в том, что вы вызываете методы из разных потоков, вы должны использовать один и тот же поток, создать свой собственный HandlerThread.

Если вы используете Realm в IntentService, вы будете использовать новый Realm. Например

 Realm.getInstance(RealmConfiguration config) 

Я использовал Realm в IntentService

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