16

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

Однако, я получил сообщение об ошибке 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); 
    } 
} 

ответ

18

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

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

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


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

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

+0

Вы можете посмотреть на мой код и скажите мне, где я проходил мимо ничего между потоками? Я не понимаю. Я честно думал, что я был в той же теме. Насколько я знаю, я только делил методы между потоками, а не пропускал любые объекты области между потоками. –

+0

Трудно понять, что происходит, когда из примера кода.Но я предполагаю, что вы получите объект result в doInBackround AsyncTask (который выполняется в рабочем потоке), а затем передайте его в результате toPostExecute() (который выполняется в основном потоке). И затем попытаемся получить доступ к нему оттуда по методу restder(), который взорвет ваше приложение. –

+0

Вы можете посмотреть в трассировке стека, которую я предоставил, чтобы увидеть путь выполнения. IntentService 'DownloadDealService' вызывает некоторые статические методы в моем классе' Util.java'. –

0

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

0

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

Realm.getInstance(RealmConfiguration config) 

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

@Override 
protected void onHandleIntent(Intent intent) { 
    Realm realm = Realm.getDefaultInstance(); 
    ... 
    realm.close(); // important on background thread 
} 
Смежные вопросы