안드로이드 NetworkOnMainThreadException 에러, Thread를 사용해야 되는 경우

 

환경: Android

 

해당 에러는 허니컴 이후부터 네트워크 관련 작업을 진행할 때 발생할 수 있습니다. 메인 Thread 에서 발생하는 에러로 네트워크를 이용해 데이터를 받기 위해서는 별개의 Thread 가 필요합니다. 그렇지 않으면 Stream 객체를 통해 데이터를 읽어 오는 과정에서 android.os.NetworkOnMainThreadException 에러가 나게 됩니다. 네트워크 처리를 잘 못하게 되면 메인 Thread 가 멈출 수 있으므로 강제로 분리해서 구현하도록 만든 것 같습니다.

 

데이터를 읽어 오는 InputStreamReader 에서 Exception 이 발생한 것입니다. 네트워크 특성상 가져오는 데이터 양이 정해져 있지 않기 때문에 Thread 를 별도로 돌려야 합니다. 그렇지 않으면 데이터를 가져오는 동안 프로그램이 멈춰 있겠죠

안드로이드 android.os.NetworkOnMainThreadException 에러, Thread를 사용해야 되는 경우

 

네트워크를 통해서 데이터를 가져오는 소스는 다음과 같습니다. 여기에 에러가 나지 않도록 Thread 를 추가하겠습니다. 데이터를 가져오는 getNaverHtml() 함수가 Thread 안에서 실행을 해야겠죠

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class NetworkActivity extends Activity {

    private TextView edtHtml;
    final int CONN_TIME = 5000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_network);
        String naverHtml = getNaverHtml();

        edtHtml = (TextView)this.findViewById(R.id.edtHtml);
        edtHtml.setText(naverHtml);
    }

    private String getNaverHtml(){
        String naverHtml = "";

        HttpURLConnection con = null;
        InputStreamReader isr = null;
        BufferedReader br = null;

        try{
            URL url = new URL("http://www.naver.com");
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(CONN_TIME);
            con.setReadTimeout(CONN_TIME);

            isr = new InputStreamReader(con.getInputStream());
            br = new BufferedReader(isr);

            String str = null;
            while ((str = br.readLine()) != null) {
                naverHtml += str + "\n";
            }

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(con != null){
                try{con.disconnect();}catch(Exception e){}
            }

            if(isr != null){
                try{isr.close();}catch(Exception e){}
            }

            if(br != null){
                try{br.close();}catch(Exception e){}
            }
        }
        return naverHtml;
    }
}

아래 소스처럼 getNaverHtml() 함수를 Thread run() 함수 안에 넣고 실행합니다. 가져온 데이터는 메인 Thread 인 화면에 데이터를 전달하기 위해서 Handler 을 사용합니다

new Thread() {
    public void run() {
        String naverHtml = getNaverHtml();

        Bundle bun = new Bundle();
        bun.putString("HTML_DATA", naverHtml);
        
        Message msg = handler.obtainMessage();
        msg.setData(bun);
        handler.sendMessage(msg);
    }
}.start();

데이터를 화면에 표시하는 Handler 소스는 다음과 같습니다. Thread 로부터 전달 받은 html 데이터를 EditText 추가합니다

Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        Bundle bun = msg.getData();
        String naverHtml = bun.getString("HTML_DATA");
        edtHtml.setText(naverHtml);
    }
};

전체 소스는 다음과 같습니다

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class NetworkActivity extends Activity {

    private TextView edtHtml;
    final int CONN_TIME = 5000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_network);
        String naverHtml = getNaverHtml();

        edtHtml = (TextView)this.findViewById(R.id.edtHtml);
        //edtHtml.setText(naverHtml);

        new Thread() {
            public void run() {
                String naverHtml = getNaverHtml();

                Bundle bun = new Bundle();
                bun.putString("HTML_DATA", naverHtml);
                
                Message msg = handler.obtainMessage();
                msg.setData(bun);
                handler.sendMessage(msg);
            }
        }.start();
    }

    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            Bundle bun = msg.getData();
            String naverHtml = bun.getString("HTML_DATA");
            edtHtml.setText(naverHtml);
        }
    };

    private String getNaverHtml(){
        String naverHtml = "";

        HttpURLConnection con = null;
        InputStreamReader isr = null;
        BufferedReader br = null;

        try{
            URL url = new URL("http://www.naver.com");
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(CONN_TIME);
            con.setReadTimeout(CONN_TIME);

            isr = new InputStreamReader(con.getInputStream());
            br = new BufferedReader(isr);

            String str = null;
            while ((str = br.readLine()) != null) {
                naverHtml += str + "\n";
            }

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(con != null){
                try{con.disconnect();}catch(Exception e){}
            }

            if(isr != null){
                try{isr.close();}catch(Exception e){}
            }

            if(br != null){
                try{br.close();}catch(Exception e){}
            }
        }
        return naverHtml;
    }
}
저작자 표시 비영리 변경 금지
신고
Posted by 녹두장군