2013-04-01 28 views
5

我从IntentService进行网络调用,但仍然收到NetworkOnMainThreadException。我的理解是IntentService总是在一个工作线程上运行,所以我很惊讶地看到这一点。关键的一点可能是我的IntentService正在调用执行网络调用的静态助手类。静态辅助类在我的主Application类中实例化。IntentService中的NetworkOnMainThreadException

我认为这仍然会在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 

SOLUTION

根本的问题是遗留代码位是在呼唤onHandleIntent明确。在上述LoginService.java:

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

这是造成onHandleIntent代码给主线程上运行,因为它是被从调用onStart事件(这显然对主线程中运行)调用。

+1

你错过了一些你的代码,所以我们可以看到发生了什么。请发布一些代码,logcat输出,并指向错误来自的行。 – MCeley

回答

4

我发现了这个问题。看看这个莫名其妙的覆盖在上面LoginService.java:

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

这是导致onHandleIntent码主线程上运行,因为它是被从在onStart事件(这显然对主线程中运行)调用。我很乐意阅读开发人员的想法!

2

您的怀疑是正确的。你正在从应用程序类实例化NetworkUtils类。不管你怎么称呼它,这都不会在后台线程中运行。

+0

这是否意味着我可以在应用程序类的其他地方实例化NetworkUtils,从而让它在后台线程上运行_and_它可以保持静态类? (去懒惰的构造函数) –

+1

hrm,即使从Application类中删除了NetworkUtils的实例,并允许它在飞行中构建仍然失败。我猜一个静态助手类根本无法工作,我必须在需要NetworkUtils的地方实例化它。 –

+0

@click_whir再次,你是正确的:) –

2

严格来说,它是一个包含静态变量的类。我强烈建议你避免使用静态变量。相反,使用Android API将对象保存在SharedPreferences或Bundles等对象中。

Android对象环境是暂时性的设计。不要在内存中持久化状态,而应将其保存在专门为其设计的对象和构造中,如Bundles和SharedPreferences。你会更快乐。试试其他的东西,最后你会试图将大量的虫子挤回到一个非常小的罐子里。

+0

hm的开发者的想法......很好的建议,我确实遇到过一些情况,就是刚刚用android模型进行更快乐的开发。这是我继承的一小部分代码,而且我(显然是错误地开始)应用Java概念,即没有状态的辅助类应该是静态类。 –

+0

是的,这里有一些自定义构造,我正在废除。应用程序范围内的BroadcastReceiver只能用于此服务的ResultReceiver。此外,静态类中的上下文仅用于获取用户反馈的字符串(R类常量),因此我将通过ResultReceiver发送更纯的结果,_then_对与调用Activity/Fragment中的反馈字符串进行比较。这将允许我对NetworkUtils的成员进行静态调用,而不必将该类的实例存储在Application类中。 原谅我缺乏声望投票你有用的反馈。 –

相关问题