2014-02-08 3 views
15

С вызовом, как:дооснащения обратного вызова на главном потоке

@GET("/user/{id}/data") 
void getUserData(@Path("id") int id, Callback<Data> cb); 

Обратный вызов должен быть выполнен в основном потоке (если не используется RxJava). Мои вопросы:

  1. Где происходит синтаксический анализ (предположим, что я использую XML-конвертер для ответа процесса). Это основная нить или другая? Это зависит от реализации конвертера?
  2. Если мне нужно включить некоторые (тяжелые) правила проверки/бизнес-правила, мне нужно создать новый поток внутри вызываемого? Или это хорошо, если это сделать в методах обратного вызова?

Я ищу способы, чтобы получить данные в моей деятельности от веб-сервиса избегая потокобезопасности управления в одиночку (или с использованием других подходов, таких как IntentService и т.д.), но боюсь использовать RxJava либо (из-за экспериментальной поддержки). Есть ли другой подход к решению этой проблемы?

+2

«Если я должен включать в себя некоторые (тяжелые) правила проверки/бизнес-правил, нужно ли мне на нерест новая резьба внутри вызываемого? " - в этом случае вы не должны * использовать * 'Callback'. Удалите его, получите 'getUserData()' return 'Data' и вызовите' getUserData() 'в фоновом потоке, например' doInBackground() '' AsyncTask'. Там вы можете выполнить остальную часть своей работы, прежде чем обновлять пользовательский интерфейс в главном потоке приложения. – CommonsWare

+0

@CommonsWare; Если я удалю обратный вызов, переоснащение вызывает синхронный вызов веб-службы, и я получаю из этого действия исключение NetworkOnMainthreadException.Другой вариант, который у меня есть, - сделать переопределение веб-сервиса из нового потока в активности, но, как я уже упоминал, я избегаю управления потоками в своем коде. Я просто хочу знать, может ли Retrofit помочь мне обрабатывать как запрос, так и ответ, без необходимости использования потоков/сервисов/обработчиков/асинхронных задач. Благодаря ! – SlowAndSteady

+2

«Если я удалю обратный вызов, модификация сделает синхронный вызов веб-службы, и я получу от ActivityOnMainthreadException». Если вы прочтете мой комментарий, я написал «вызов' getUserData() 'в фоновом потоке». «Я избегаю управления потоками в своем коде» - IMHO, что не будет эффективным подходом к разработке. Использование сторонней библиотеки для обработки конкретных проблем, связанных с потоками, прекрасно; говоря, что вы сами отказываетесь заниматься нитями, непрактично. – CommonsWare

ответ

19

Где происходит синтаксический анализ (предположим, что я использую XML-конвертер для ответа процесса). Это основная нить или другая? Это зависит от реализации конвертера?

Всегда фоновая нить вне зависимости от используемого вами конвертера.

Если мне нужно включить некоторые (тяжелые) правила проверки/бизнес-правила, нужно ли мне порождать новый поток внутри вызываемого? Или это хорошо, если это сделать в методах обратного вызова?

Это довольно субъективно, и есть много способов справиться с этим. Callback будет выполняться по основному потоку по умолчанию.

Вы можете изменить поток, на который будут вызываться обратные вызовы, путем подачи пользовательского Executor на RestAdapter.Builder. Это повлияет на все службы, созданные этим RestAdapter, однако, возможно, это не то, что вы хотите.

Нет ничего плохого в том, чтобы создать новый поток (или enqueueing on the executor) из Callback, если работа, которую вы хотите выполнить, может быть выполнена параллельно с обновлением пользовательского интерфейса (например, легким кэшированием).

Если перед уведомлением пользовательского интерфейса необходимо выполнить дорогостоящую работу, вам лучше переключить метод на синхронный (без обратного вызова) и выполнить прошивку самостоятельно. Таким образом, вы можете делать дорогостоящие операции до и после HTTP-вызова (файл ввода/вывода, кэширование, преобразование, проверка и т. Д.).

В настоящее время мы используем RxJava (из которых дооснащения имеет экспериментальную поддержку) за то, что вы спрашиваете:

interface Foo { 
    @GET("/") 
    Observable<Foo> getFoo(String bar); 
} 

foo.getFoo() 
    .mapMany(new ExpensiveOperationFunction()) 
    .observeOn(AndroidSchedulers.mainThread()) 
    .subscribe(new Observer<TransformedFoo>() { .. }); 
+0

Спасибо большое! Я поставляю Исполнителя для запуска всех обратных вызовов в другом пуле. Я использую EventBus, чтобы отправить его обратно в основной поток, когда это будет сделано. Теперь все кажется хорошим, но мне было любопытно, почему мне нужно передать 2 Executors в методе setExecutor() (RestAdapter.Builder). Могу ли я передать значение null для httpExecutor (при условии, что я в порядке со значением по умолчанию). Что делать, если я передаю один и тот же исполнитель как для httpExecutor, так и для callbackExecutor? – SlowAndSteady

+2

В соответствии с документами передача null для второго (обратного) исполнителя вызовет обратный вызов в том же потоке, который запускает HTTP-запрос. Вы не можете передать значение null для исполнителя HTTP. –

+0

'' 'Всегда фоновая нить вне зависимости от используемого вами конвертера.' '' Это тоже верно для retrofit2? – gaara87