블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


오늘은 Android Tablet Developer's Cook Book에 나오는 JSON 관련 예제를 공부할 겁니다.


Chapter 15에 나오는 예제인데요. ConsumeJSONWebserviceApp 이라는 프로젝트 입니다.


일단 SampleJSON.php 라는 파일이 아래 경로에 있습니다.


http://www.gosolkit.com/SampleJSON.php


이 php가 만들어낸 json 데이터는 아래와 같습니다.


[{"state":"Alabama","capital":"Montgomery","latitude":"32.361538","longitude":"-86.279118"},{"state":"Alaska","capital":"Juneau","latitude":"58.301935","longitude":"-134.419740"},{"state":"Arizona","capital":"Phoenix","latitude":"33.448457","longitude":"112.073844"},{"state":"California","capital":"Secramento","latitude":"36.448457","longitude":"112.073844"},{"state":"Gangwon","capital":"Chunchon","latitude":"33.448457","longitude":"112.073844"},{"state":"Rhode Island","capital":"Providence","latitude":"33.448457","longitude":"112.073844"},{"state":"New Jersey","capital":"Trenton","latitude":"33.448457","longitude":"112.073844"}]

위 URL은 책에 있는 URL이랑은 다릅니다.

제 개인 URL 을 사용했구요. json 데이터도 안에 그 내용을 조금 더 추가했습니다.


원격에 있는 php로 생성한 JSON 파일을 받아와서 안드로이드 앱에서 사용하는 예제 입니다.


우선 첫번째로 layout xml 파일을 보죠.


activity_consume_jsonwebservice_app.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"> 
    <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/state_name"
            android:hint="Enter State Name" 
                android:textSize="@dimen/text_size"   />
    <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/submit_btn"
            android:text="Submit"
                android:textSize="@dimen/text_size" />
    <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/response"
                android:textSize="@dimen/text_size" />
</LinearLayout>


LinearLayout으로 감쌌고 orientation은 vertical 입니다.

그 안에 EditText와 Button 그리고 TextView 이렇게 세개의 view 가 있습니다.



EditText에 주 이름을 넣고 Submit 버튼을 누르면 그 아래 TextView에 원격에서 받은 JSON 데이터를 파싱해서 뿌려 줄 건가 봅니다.


그러면 이제 자바 파일을 보죠.


ConsumeJSONWebserviceAppActivity.java


public class ConsumeJSONWebserviceAppActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_consume_jsonwebservice_app);
        Button submitButton = (Button)this.findViewById(R.id.submit_btn);
        submitButton.setOnClickListener(new Button.OnClickListener(){
             public void onClick(View v)  { 
                    new ReadJSONFeed().execute("http://www.gosolkit.com/SampleJSON.php");               
             }
        });
    }
     
    private class ReadJSONFeed extends AsyncTask<String, String, String> {
        protected void onPreExecute() {}

        @Override
        protected String doInBackground(String... urls) {
       HttpClient httpclient = new DefaultHttpClient();
       StringBuilder builder = new StringBuilder();
            HttpPost httppost = new HttpPost(urls[0]);
           try {
           HttpResponse response = httpclient.execute(httppost);
        StatusLine statusLine = response.getStatusLine();
       int statusCode = statusLine.getStatusCode();
       if (statusCode == 200) {
            HttpEntity entity = response.getEntity();
            InputStream content = entity.getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(content));
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }     
    return builder.toString();
        }

        protected void onPostExecute(String result) {
            String state="";
            String stateInfo="";
            EditText stateName = (EditText) findViewById(R.id.state_name);
            String searchState=stateName.getText().toString();
            try{
             JSONArray countriesArray = new JSONArray(result);       
                   for (int i =0 ; i<countriesArray.length();i++) {
                       JSONObject jObject = countriesArray.getJSONObject(i);
                      state = jObject.getString("state");
                      if(searchState.equalsIgnoreCase(state))
                      {
                          stateInfo+="Capital: "+jObject.getString("capital")+"\n";
                          stateInfo+="Latitude: "+jObject.getString("latitude")+"\n";
                          stateInfo+="Longitude: "+jObject.getString("longitude")+"\n";
                      }
                   }
            }
             catch (JSONException e) {
                 e.printStackTrace();
                 }
            TextView resp = (TextView) findViewById(R.id.response);
            if(stateInfo.trim().length() >0 )
             resp.setText(stateInfo);   
            else
                resp.setText("Sorry no match found");
        }
    }
}



그렇게 복잡한거 같지는 않죠?


먼저 onCreate()를 보죠.

activity_consume_jsonwebservice_app.xml 을 Layout 으로 사용한다고 세팅했습니다.

바로 위에서 본 xml 입니다.


그리고 버튼에 대한 객체를 만들고 이 버튼에 onClickListener를 달았습니다.

이 버튼을 클릭하면 ReadJSONFeed() 라는 클래스를 호출하네요. 그리고 excute() 라는 메소드에 아까 소개했던 원격 URL 을 pass 합니다.


그러면 ReadJSONFeed() 클래스를 보겠습니다.

이 클래스는 AsyncTask 를 상속합니다.

여기를 보시면 해당 API를 보실 수 있습니다.


UI thread를 쉽게 사용할 수 있게 해 준다고 하네요. background 로 실행되게 해서 그 결과를 UI thread에 publish 하는 군요. 따로 thread나 handler들을 작성하지 않아도 된다고 하네요.

이 AsyncTask는 짧은 기간 동안 수행할 작업에 사용됩니다. 만약 긴 기간동안 수행할 작업을 쓰레드로 사용하시려면 Executor, ThreadPoolExecutor and FutureTask 같은 java.util.concurrent pacakge 를 사용 하셔야 합니다.

이 asynchronous task(비동기 작업)은 Params, Progress and Result 이렇게 3가지가 있고 4개의 step들이 있습니다.

onPreExecute, doInBackground, onProgressUpdate and onPostExecute


그러면 계속 ReadJSONFeed 클래스를 보겠습니다.

첫번째 줄에는 위에 봤든 onPreExecute() 메소드가 있네요. 그 안에는 아무것도 없구요.

그냥 넘어가도 되겠습니다.


그 다음에는 또 위에서 봤던 doInBackground() 메소드가 나옵니다.

이 안에 어떤 로직을 넣으면 Background 로 돌아가게 됩니다.


우선 HTTPClient와 HttpPost, StringBuilder 를 초기화 했습니다.

HttpResponse를 초기화 하면서 httpclient의 execute메소드를 통해 httppost를 pass 해 줍니다.

여기 httppost에는 아까 버튼 눌렀을 때 pass 했던 url이 들어 있습니다.

그러면 response 안에 그 결과값 즉 json 데이터들이 담기겠죠.

그 다음에는 StatusLine을 초기화 하면서 이 response의 line을 get 합니다.

즉 json 내용을 get 하는거죠.

그리고 이 statusLine 의 statusCode를 statusCode라는 변수에 담습니다.

이 statusCode에는 성공했는지 실패 했는지에 대한 정보가 담기겠죠.

다음 if 문에서는 만약에 이 작업이 성공했으면 HttpEntity 를 생성해서 여기에 response의 Entity를 가져 옵니다. 그리고 그 내용을 InputStrean에 담고요.

다음에 BufferedReader를 이용해서 그 내용을 읽습니다.


Java에서 파일 내용을 읽어 들일 때 사용하는 InputStream과 BufferedReader가 여기서도 사용되네요.

그 다음에 line이라는 String을 만들어서 모든 줄을 이 line에 넣습니다.


여기까지가 doInBackground() 메소드가 하는 일입니다.

간단하네요. 원격에 있는 정보를 가져와서 이것을 사람이 읽을 수 있는 정보로 line이라는 String에 담은 겁니다.


그 다음에 실행되는 메소드는 onPostExecute() 입니다.

한번 볼까요?


state, stateInfo 라는 String을 만들었습니다. 주 이름과 그 주에 대한 정보를 담을 변수들 인 것 같습니다.

그리고 layout xml에서 만든 EditText에 대한 변수를 만들었습니다.


그리고 searchState라는 String에 이 stateName의 내용을 담을 겁니다.


다음에 나오는 내용들은 JSON을 파싱하는 로직 입니다.

아까 doInBackGround에서는 line이라는 String에 이 JSON 데이터를 그냥 담았죠.

이것을 파싱해서 사람이 알아볼 수 있도록 화면에 뿌려줄 겁니다.


onPostExecute(String result) 라고 위에 돼 있죠. 여기서는 pass 받은 string을 result 라는 변수이름으로 사용할 겁니다.


보시면 이 result 를 countriesArray라는 JSONArray 에 담습니다.


그 다음 for 문을 돌려서 아까 만들었던 변수들에 해당 내용들을 담습니다.

state에는 주 이름이 그리고 searchState에 있는 내용들은 Capital, Latitude, Longitute 별로 따로 사람이 읽기 좋게 편집해서 stateInfo에 담습니다.


그 다음에는 try catch 문 밖을 보시면 되는데요.


TextView 객체를 만들었죠.

이 text 뷰에 위에 만들었던 stateInfo를 setText() 해서 화면에 표시합니다.


그러면 아래와 같은 화면을 보실 수 있습니다.





여기서의 주요 개념은 AsyncTask 를 이용해서 쉽게 Background 작업을 하도록 한다는 것과

원격의 데이터를 받아 오는 방법 여기서는 HttpClient, StringBuilder, HttpPost, HttpResponse 등이 사용됐습니다. 그리고 이 데이터를 바이너리 형태로 돼 있을 텐데 이것을 InputStream과 BufferedReader를 이용해서 사람이 읽을 수 있는 문자로 파싱하는 방법을 배웠습니다.

그리고 그 파싱된 JSON 타입을 다시 key 값을 이용해서 value를 가져와서 필요에 따라 편집하는 방법도 배웠습니다.


아주 중요한 개념들이 많네요.


안드로이드 앱과 웹 서비스와의 네트워킹도 아주 쉽게 사용할 수 있도록 만들었군요.