2013-04-01 29 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類中。 原諒我缺乏聲望投票你有用的反饋。 –

相關問題