12

I tried multiple HTTP classes (HttpURLConnection, HTTPClient and others) but they don't work in emulator. Then I decided to test that on my phone and it worked well!

So how can I fix this strange behaviour of Android emulator that HTTP classes don't work (while browser can work)? They crash an application at all.

Here is my code:

public static SimpleXML getResponse(String action, Map<String, String> params) {
     // Create a new HttpClient and Post Header
    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httppost = new HttpPost(action);

    try {
        // Add your data
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(params.size());
        for(Map.Entry<String, String> heh : params.entrySet())
            nameValuePairs.add(new BasicNameValuePair(heh.getKey(), heh.getValue()));
        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        // Execute HTTP Post Request
        HttpResponse response = httpclient.execute(httppost);
        return SimpleXML.loadXml(response.getEntity().getContent());       

    } catch (ClientProtocolException e) {
        return null;
    } catch (IOException e) {
        return null;
    }   
}

LogCat log:

06-30 22:07:28.972: E/AndroidRuntime(682): FATAL EXCEPTION: main
06-30 22:07:28.972: E/AndroidRuntime(682): android.os.NetworkOnMainThreadException
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
06-30 22:07:28.972: E/AndroidRuntime(682):  at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
06-30 22:07:28.972: E/AndroidRuntime(682):  at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
06-30 22:07:28.972: E/AndroidRuntime(682):  at java.net.InetAddress.getAllByName(InetAddress.java:214)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:137)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
06-30 22:07:28.972: E/AndroidRuntime(682):  at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
06-30 22:07:28.972: E/AndroidRuntime(682):  at net.ekvium.air.API.getResponse(API.java:98)
06-30 22:07:28.972: E/AndroidRuntime(682):  at net.ekvium.air.MainActivity$1.onClick(MainActivity.java:62)
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.view.View.performClick(View.java:4084)
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.view.View$PerformClick.run(View.java:16966)
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.os.Handler.handleCallback(Handler.java:615)
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.os.Handler.dispatchMessage(Handler.java:92)
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.os.Looper.loop(Looper.java:137)
06-30 22:07:28.972: E/AndroidRuntime(682):  at android.app.ActivityThread.main(ActivityThread.java:4745)
06-30 22:07:28.972: E/AndroidRuntime(682):  at java.lang.reflect.Method.invokeNative(Native Method)
06-30 22:07:28.972: E/AndroidRuntime(682):  at java.lang.reflect.Method.invoke(Method.java:511)
06-30 22:07:28.972: E/AndroidRuntime(682):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
06-30 22:07:28.972: E/AndroidRuntime(682):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
06-30 22:07:28.972: E/AndroidRuntime(682):  at dalvik.system.NativeStart.main(Native Method)
Nate
  • 31,017
  • 13
  • 83
  • 207
Uhehesh
  • 506
  • 2
  • 8
  • 22

3 Answers3

20

If you look at this Android documentation, it explains

NetworkOnMainThreadException:

The exception that is thrown when an application attempts to perform a networking operation on its main thread.

This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.

So, depending on OS version, there may be enforcement (exception throwing) of the policy that you not make network requests on the UI thread. This could explain why your code works on a device, and not on an emulator (if they have different Android versions).

You could change the ThreadPolicy. But as an alternative, I'd suggest you look again at the statement in the Android docs. They heavily discourage performing network operations on the main thread, and I'd certainly agree with them.

So, rather than changing the policy to make it legal, you might consider changing your code, so that your getResponse() method is not called on the UI thread.

Typically, you would use AsyncTask to do the work in the background.

Nate
  • 31,017
  • 13
  • 83
  • 207
  • Nice. That's probably even better than that solution with permitAll(). But I have a question. I am making authorization. How should I do it with AsyncTask? I send login and password using POST. – Uhehesh Jun 30 '12 at 22:36
  • @Uhehesh, Just wanted to give you another option. As usual, there's more than one way to solve a problem :) – Nate Jun 30 '12 at 22:43
  • @Uhehesh, I was just saying that you **can** solve the problem by changing `ThreadPolicy`, as the other answer describes. **Or**, you could change your code to not call `getResponse()` on the main/UI thread. Both will stop your program from crashing with that exception. But, if you just change `ThreadPolicy`, your UI will be frozen while the network request is being performed. If that takes more than a fraction of a second, the user may not be happy. – Nate Jun 30 '12 at 22:47
  • yes, I don't like that and I want another way to do that. Not in the main thread. – Uhehesh Jun 30 '12 at 22:48
  • @Uhehesh, I agree. Look at the `AsyncTask` link in my answer above. – Nate Jun 30 '12 at 22:49
  • that's OK. But my code crashes. Maybe because I call Toast inside AsyncTask? So I shouldn't call Toast there but to move it to main thread, yes? – Uhehesh Jun 30 '12 at 23:09
  • @Uhehesh, I can't tell without seeing how you use `Toast`. You should probably just start a new question, posting the code that uses `AsyncTask` and `Toast`, and tell us what's not working. That's really a different problem than why you got the `NetworkOnMainThreadException`. – Nate Jun 30 '12 at 23:12
  • 1
    okay, really. Thank you for answer though! No more discussion in comments. – Uhehesh Jun 30 '12 at 23:13
15

This happens because you try to perform network activity on the main thread.

I had the same issue, It worked for a while, then after a few weeks of developing, it stopped working.

The solution I found was to add these lines to the

onCreate()

Method:

    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);

Hope this works for you too

EDIT

Due to increasing number of upvotes, I wish to add something. This will remove the NetworkingOnMainThreadException, HOWEVER, it is by far not a recommended way.

This exception is there for a reason. Network activity can take time, performing networking on the main thread, which is the same thread that responsible for updating the UI, would freeze the thread until the networking is done (this is what happens on every thread, but when it's performed on a dedicated thread, it's ok). In Android, if the UI-thread isn't active for 5 seconds, it will show the Application is not responsive, Do you want to close it? dialog.

This is what the exception has come to prevent. Setting the policy, like I suggested, while removes the exception, is the wrong way of doing things. Any networking actions should be done on a separate thread, either by using AsyncTask or by creating new Thread manually. AsyncTask are a very easy and straight-forward way of implementing this, and this is what I recommend.

Please take this edit into consideration when using my answer.

Cheers

La bla bla
  • 8,558
  • 13
  • 60
  • 109
  • Any downvoters, your opinions counts more than just a downvote. if you think this solution isn't good, say it. don't just mark it. this way both the one who asked and me, could improve... Because when I found this answer, it had like 15 up votes... – La bla bla Jun 30 '12 at 22:18
  • Brilliant. It helped me! I would vote up but I don't have enough reputation. – Uhehesh Jun 30 '12 at 22:23
  • I didn't down vote your answer (good to know how to change policies!), and I agree that down voters should comment, but the downside of doing this is that it's really subverting Android's recommendation to not perform network requests on the UI thread. Normally (but not always, of course), that's good advice. – Nate Jun 30 '12 at 22:30
0

You disable the strict mode using following code:

if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = 
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}

This is not recommended: use the AsyncTask interface.

Link of AsyncTask

Link of another reference

Community
  • 1
  • 1
DarckBlezzer
  • 4,578
  • 1
  • 41
  • 51