2013-04-01 6 views
5

Я делаю сетевые вызовы из IntentService, но все же получаю сообщение NetworkOnMainThreadException. Я понимаю, что IntentService всегда работает на рабочем потоке, поэтому я удивлен, увидев это. Ключевым моментом может быть то, что мой IntentService вызывает статический вспомогательный класс, который выполняет сетевые вызовы. Статический вспомогательный класс создается в моем основном классе Application.NetworkOnMainThreadException в IntentService

Я думал, что это все равно будет выполняться на рабочем потоке IntentService. Что мне не хватает?

Честно говоря, я предпочитаю пьянящие информативные обсуждения по быстрому исправлению кода. Но если требуется код, должен быть предусмотрен код:

//MyApplication.java 
public class MyApplication extends Application{ 

private static NetworkUtils utils; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 
     utils = new NetworkUtils(this); 
     ... 
    } 
    ... 
} 

//NetworkUtils.java 
public class NetworkUtils { 

    private static Context context; 
    private static final Gson gson = new Gson(); 

    public NetworkUtils(Context context) { 
     this.context = context; 
    } 

    public static final DataResponse login(String email, String password) { 
     //*** NetworkOnMainThreadException OCCURS HERE *** 
     DataResponse response = HttpConnection.put(url, json); 
     ... 
     return response; 
    } 
    ... 
} 

//LoginService.java 
public class LoginService extends IntentService { 

    public LoginService() { 
     super("LoginService"); 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
     onHandleIntent(intent); 
    } 

    @Override 
    protected void onHandleIntent(Intent intent) { 
     Bundle bundle = new Bundle(); 
     DataResponse response = NetworkUtils.login(email, password); 
     ... 
     bundle.putBoolean(MyConstants.ExtraKeys.LOGGED, response.success); 
     MainApplication.getApplicationInstance().sendBroadCast(MyConstants.Actions.LOGIN, bundle); 
    } 
} 

//LoginActivity.java 
public class LoginActivity extends ActionBarActivity implements IDialogClickListener { 
    ... 
    public void onLoginButtonPressed() { 
     Intent intent = new Intent(MainApplication.getApplicationInstance(), LoginService.class); 
     this.startService(intent); 
    } 
} 

Кроме того, LogCat:

> 04-01 18:20:41.048: VERBOSE/com.foo.foo(28942): 
>  com.foo.foo.network.HttpConnection.execute - METHOD: PUT 
> 04-01 18:20:41.068: ERROR/com.foo.foo(28942): 
>  com.foo.foo.social.NetworkUtils.login - class 
>  android.os.NetworkOnMainThreadException: null 
> 04-01 18:20:41.169: DEBUG/com.foo.foo(28942): 
>  com.foo.foo.MainActivity$MyReceiver.onReceive - BROADCAST RECEIVED: 
>  [email protected] - Intent { act=com.foo.foo.login 
>  dat=com.foo.foo.scheme://data/1364854841079 (has extras) } 
> 04-01 18:20:41.169: INFO/com.foo.foo(28942): 
>  com.foo.foo.activity.LoginActivity.setData - ACTION: com.foo.foo.login 
>  - ISERROR: true 

РЕШЕНИЕ

Основная проблема была немного унаследованного кода, который звонил onHandleIntent явно , В LoginService.java выше:

@Override 
public void onStart(Intent intent, int startId) { 
    onHandleIntent(intent); 
} 

Это вызывает код onHandleIntent для запуска на главном потоке, так как она вызывается из OnStart события (который, видимо, работает на основном потоке).

+1

Вам не хватает части кода, чтобы мы могли видеть, что происходит. Пожалуйста, разместите код, вывод логарифма и укажите на строку, из которой исходит ошибка. – MCeley

ответ

4

Я заметил проблему. Проверьте это озадачивает переопределение LoginService.java выше:

@Override 
public void onStart(Intent intent, int startId) { 
    onHandleIntent(intent); 
} 

Это вызывает onHandleIntent код для запуска в главном потоке, так как она вызывается из OnStart события (который, видимо, работает на основном потоке). Я хотел бы прочитать ум разработчика, который положил это!

2

Ваши подозрения верны. Вы создаете класс NetworkUtils из своего класса приложения. Это не будет работать в фоновом потоке, как бы вы это ни называли.

+0

Означает ли это, что я могу создать экземпляр NetworkUtils в другом месте из класса приложения и, таким образом, заставить его работать в фоновом потоке _and_, он может оставаться статическим классом? (уходит, чтобы экспериментировать с ленивым конструктором) –

+1

hrm, даже удалив экземпляр NetworkUtils из класса Application и позволяя ему строить «на лету», все еще терпит неудачу. Я предполагаю, что статический вспомогательный класс вообще не работает, и я должен создавать его локально везде, где требуется NetworkUtils. –

+0

@click_whir снова, вы правы :) –

2

Строго говоря, это класс, содержащий статические переменные. Я настоятельно рекомендую избегать статических переменных. Вместо этого используйте Android API для сохранения состояния в таких объектах, как SharedPreferences или Bundles.

Окружающая среда Android является преходящей по дизайну. Вместо сохранения состояния в памяти сохраняйте его в объектах и ​​конструкциях, специально предназначенных для него, таких как Bundles и SharedPreferences. Вы будете намного счастливее. Попробуйте что-нибудь еще, и вы в конечном итоге попытаетесь выжать большую массу червей обратно в очень маленькую банку.

+0

hm ... хороший совет, я действительно столкнулся с ситуациями, когда только что идет с моделью Android, для более счастливого развития. Это немного кода, который я унаследовал, и я (по-видимому, ошибочно) применяю понятие Java, что вспомогательные классы, которые не имеют состояния, должны быть статическими классами. –

+0

Да, есть некоторые пользовательские конструкции, с которыми я сталкиваюсь. Широковещательный широковещательный широковещательный канал для всей службы превращается в ResultReceiver только для этой услуги. Также Контекст в статическом классе существует только для того, чтобы получить строки (константы класса R) для обратной связи с пользователем, поэтому я собираюсь отправить более чистый результат через ResultReceiver, _then_ pair, который с цепочками обратной связи в вызывающей Activity/Fragment. Это позволит мне делать статические вызовы членам NetworkUtils и не хранить экземпляр указанного класса в классе Application. Простите, что мне не хватает репутации, чтобы проголосовать за вашу полезную обратную связь. –

Смежные вопросы