본문 바로가기

안드로이드

android.os.NetworkOnMainThreadException 예외가 발생했을 경우

android.os.NetworkOnMainThreadException 예외가 발생했을 경우

분류없음 2011/08/07 11:09
안드로이드를 적용할 시스템때문에 세부내용을 하나씩 학습중이다.
대상이 되는 장비가 태블릿이므로 안드로이드 3.1(허니컴)을 기준으로 예제코딩중...

사용자정의 layout 및 adapter에 대한 학습예제를 따라하던 중 제목과 같은 예외를 접하게 됐다.

예외가 발생한 상황은 main Activity에서 tweet search결과값을 얻어오기 위해 메소드에서 였다.

다음 코드는 croute님의 blog post(http://croute.me/413) 중 일부분이다. 
(croute 블로그에는 좋은 글과 예제코드가 많이 올라와 있다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void getTweets() {
 
    HttpClient client = new DefaultHttpClient();
    HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
    HttpGet httpGet = new HttpGet(mUrl);
     
    try{
        HttpResponse response = client.execute(httpGet);
        processTweetEntity(response.getEntity());
    }
    catch(ClientProtocolException e){
        e.printStackTrace();
    }
    catch(IOException e){
        e.printStackTrace();
    }
}
사실 위 코드에는 문제가 전혀 없다.
문제는 android가 변했다는 점이다.

결론부터 말하자면 honeycomb에서는 main thread(UI)에서 네트워크 호출을 하면 무조건 error로 간주한다.

앱 전체의 thread와 컨트롤을 관리하는 main에서 네트워크 호출로 대기중인 시간이 길어지면
사용자는 안드로이드앱의 문제로 인식하게 된다. 이를 방지하자는 것이 목적이다.
다음 링크를 참조하자 : painless threading , painless threading 번역글

코드는 아래와 같이 바뀌어야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// RetriveTweetTask 클래스를 생성하고 필요한 인수를 전달하여 실행시킨다.
 private void getTweets() {      
      new RetriveTweetTask().execute(mUrl);
 }
 
 // AsyncTask<Params,Progress,Result>
 private class RetriveTweetTask extends AsyncTask<String, Void, HttpResponse>{
 
      @Override
      protected HttpResponse doInBackground(String... urls) {
           
          HttpResponse response = null;
          HttpClient client = new DefaultHttpClient();
          HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
          HttpGet httpGet = new HttpGet(urls[0]);
          try {
              response = client.execute(httpGet);
          }
          catch(ClientProtocolException e){
              e.printStackTrace();
          }
          catch(IOException e) {
              e.printStackTrace();
          }
           
          return response;
      }
 
      @Override
      protected void onPostExecute(HttpResponse result) {
          //super.onPostExecute(result);     
          try {
              processTweetEntity(result.getEntity());
          } catch (UnsupportedEncodingException e) {
              e.printStackTrace();
          } catch (IllegalStateException e) {
              e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  }
하지만, 코드를 이만큼 수정해도 예외는 사라지지 않는다. 진저브레드에서 추가된 새로운 API때문이다.
그것은 StrictMode.. 다음 링크를 참고하자 : StrictMode StrictMode번역

링크의 글을 자세히 읽어보면 알게 되겠지만 thread를 사용하게 될 경우 제약조건을 정의하고 있다.
특정 thread에서 일어나서는 안되는 일들을 규약으로 정해야 하며 이를 어겼을 경우 예외가 발생한다.
위 링크에서 추천하는 방식으로 개발 모드에 사용해야 할 StrictMode를 코드에 추가해야 
예외 메시지에서 벗어날 수 있다.