안드로이드 오답노트 에서 퍼온글입니다. 
안드로이드 개발 삽질 기록 노트

2010/08/24 19:07

이번 예제에서는 안드로이드에서 POST혹은 GET 방식으로 웹서버에 데이터를 주고받아보도록 하겠습니다. 서버사이드 언어는 PHP를 이용하였습니다. 서버 환경은 APM_SETUP을 이용하여 Localhost에 구동시켰습니다.

해결책

HttpPost 혹은 HttpGet을 이용하여 nameValue 데이터를 웹서버에 보내고 응답 메세지를 받는다.

토의

먼저, 서버 사이드에서 받은 응답을 처리할 PHP 코드를 간단히 아래와 같이 구성합니다.

  1. <?php  //androidnote.co.kr $name = $_REQUEST['name'] ; $sex = $_REQUEST["sex"] ;  echo "My Name is ".$name." and ".$sex."!" ;  ?>   

위 코드는, GET 혹은 POST Method 방식으로 넘어온 데이터 값을 바탕으로 문자열을 반환하는 간단한 PHP 코드입니다.

이제 클라이언트 측인 안드로이드로 넘어가겠습니다. 먼저 인터넷을 사용할 수 있도록 AndroidManifest.xml 파일을 열어서 다음과 같이 인터넷 퍼미션을 추가하여 줍니다.

  1. <!--?xml version="1.0" encoding="utf-8"?-->  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="kr.co.androidnote.webserver" android:versioncode="1" android:versionname="1.0">  
  3.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  4.         <activity android:name=".WebServerMain" android:label="@string/app_name">  
  5.             <intent-filter>  
  6.                 <action android:name="android.intent.action.MAIN">  
  7.                 <category android:name="android.intent.category.LAUNCHER">  
  8.             </category></action></intent-filter>  
  9.         </activity>  
  10.   
  11.     </application>  
  12.     <uses-sdk android:minsdkversion="7">  
  13.   
  14. <uses-permission android:name="android.permission.INTERNET"></uses-permission>  
  15. </uses-sdk></manifest>   

다음으로는, 안드로이드에서 사용자 이름과 성별을 입력받고, 데이터를 보내는 이벤트를 발생 시킬 수 있는 버튼으로 레이아웃을 아래와 같이 구성합니다. 서버로 부터 응답 받은 데이터를 출력할 TextView도 구성합니다.

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     >  
  7. <TextView    
  8.     android:layout_width="fill_parent"   
  9.     android:layout_height="wrap_content"   
  10.     android:text="Enter Your Name"  
  11.     />  
  12. <EditText   
  13.     android:layout_width="fill_parent"   
  14.     android:layout_height="wrap_content"  
  15.     android:id="@+id/nameF"   
  16. />  
  17. <TextView    
  18.     android:layout_width="fill_parent"   
  19.     android:layout_height="wrap_content"   
  20.     android:text="Enter Your Sex"  
  21.     />  
  22. <EditText   
  23.     android:layout_width="fill_parent"   
  24.     android:layout_height="wrap_content"  
  25.     android:id="@+id/sexF"   
  26. />  
  27. <TextView   
  28.     android:layout_width="fill_parent"   
  29.     android:layout_height="wrap_content"  
  30.     android:id="@+id/resultF"  
  31.     android:text="Result Field"  
  32. />  
  33. <Button   
  34.     android:layout_width="fill_parent"   
  35.     android:layout_height="wrap_content"  
  36.     android:id="@+id/submitBtn"  
  37.     android:text="Submit"  
  38. />  
  39. </LinearLayout>  

이제는 버튼이 클릭되면 서버로 데이터를 보내고 서버로 부터 응답 메세지를 받아서 다시 클라이언트 측에 출력하는 과정을 구현해야 합니다. 그런데 이 모든 과정이 동기적으로 일어나게 된다면 서버에 데이터를 보내고 다시 응답을 받아올 때까지 어플리케이션은 먹통이 되고 맙니다.

이러한 이슈를 해결하기 위해서는 프로세스를 비동기적으로 처리해야 하는데, 이때 사용하는 방법이 Thread를 이용하는 방법과 안드로이드에서 제공하는 AsyncTask라는 Helper 클래스를 사용할 수 있습니다.

보통 AsyncTask나 Thread를 사용하거나 원하는 것을 구현할 수 있는데, AsyncTask는 Thread의 생성과 실행을 추상화 시킴으로써 좀더 좋은 사용성을 제공하여 주고 있습니다. AsyncTask에 대해 자세하게 설명된 블로그를 소개함으로써 다시 주된 관심사로 돌아오도록 하겠습니다.

결론은 웹서버 연동 로직은 비동기적으로 처리해야 하지만 이번 예제의 목적은 간단히 데이터를 주고 받아오는 것을 보이는 것이기 때문에 가독성을 고려해서 동기적으로 모든 절차를 처리하였습니다.

아래는 그 절차 코드를 보여주고 있습니다.

  1. package kr.co.androidnote.webserver;  
  2.   
  3. import ......(생략)  
  4.   
  5. public class WebServerMain extends Activity implements OnClickListener {  
  6.     /** Called when the activity is first created. */  
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.main);  
  11.           
  12.         Button btn = (Button) findViewById( R.id.submitBtn ) ;  
  13.         btn.setOnClickListener( this ) ;  
  14.     }  
  15.   
  16.     @Override  
  17.     public void onClick(View v) {  
  18.         // TODO Auto-generated method stub  
  19.         String name = ((EditText) findViewById(R.id.nameF)).getText().toString() ;  
  20.         String sex = ((EditText) findViewById(R.id.sexF)).getText().toString() ;  
  21.         TextView resultField = ( TextView ) findViewById( R.id.resultF ) ;  
  22.           
  23.         try {  
  24.             //데이터를 웹서버에 보내고 받아온 결과를 출력합니다.  
  25.             resultField.setText( sendData( name, sex ) ) ;  
  26.         } catch (ClientProtocolException e) {  
  27.             // TODO Auto-generated catch block  
  28.             e.printStackTrace();  
  29.         } catch (IOException e) {  
  30.             // TODO Auto-generated catch block  
  31.             e.printStackTrace();  
  32.         }  
  33.     }  
  34.   
  35.     private String sendData(String name, String sex) throws ClientProtocolException, IOException {  
  36.         // TODO Auto-generated method stub  
  37.         HttpPost request = makeHttpPost( name, sex, "http://192.168.10.4/php_post_example.php" ) ;  
  38.           
  39.         HttpClient client = new DefaultHttpClient() ;  
  40.         ResponseHandler<string> reshandler = new BasicResponseHandler() ;  
  41.         String result = client.execute( request, reshandler ) ;  
  42.         return result ;  
  43.     }  
  44.   
  45.     private HttpPost makeHttpPost(String $name, String $sex, String $url) {  
  46.         // TODO Auto-generated method stub  
  47.         HttpPost request = new HttpPost( $url ) ;  
  48.         Vector<namevaluepair> nameValue = new Vector<namevaluepair>() ;  
  49.         nameValue.add( new BasicNameValuePair( "name", $name ) ) ;  
  50.         nameValue.add( new BasicNameValuePair( "sex", $sex ) ) ;  
  51.         request.setEntity( makeEntity(nameValue) ) ;  
  52.         return request ;  
  53.     }  
  54.       
  55.     private HttpEntity makeEntity( Vector<namevaluepair> $nameValue ) {  
  56.         HttpEntity result = null ;  
  57.         try {  
  58.             result = new UrlEncodedFormEntity( $nameValue ) ;  
  59.         } catch (UnsupportedEncodingException e) {  
  60.             // TODO Auto-generated catch block  
  61.             e.printStackTrace();  
  62.         }  
  63.         return result ;  
  64.     }  
  65. }  
  66. </namevaluepair></namevaluepair></namevaluepair></string>  

위의 방식은 HttpPost를 이용하여 POST Method를 사용한 예제이며, Get 방식은 아래와 같이 sendData 메서드 내의 request를 HttpGet으로 변경해 주면 됩니다.

  1.     private String sendData(String name, String sex) throws ClientProtocolException, IOException {  
  2.         // TODO Auto-generated method stub  
  3. //      HttpPost request = makeHttpPost( name, sex, "http://192.168.10.4/php_post_example.php" ) ;  
  4.         HttpGet request = makeHttpGet( name, sex, "http://192.168.10.4/php_post_example.php" ) ;  
  5.         HttpClient client = new DefaultHttpClient() ;  
  6.         ResponseHandler<string> reshandler = new BasicResponseHandler() ;  
  7.         String result = client.execute( request, reshandler ) ;  
  8.         return result ;  
  9.     }  
  10.   
  11.     private HttpGet makeHttpGet(String $name, String $sex, String $url) {  
  12.         // TODO Auto-generated method stub  
  13.         Vector<namevaluepair> nameValue = new Vector<namevaluepair>() ;  
  14.         nameValue.add( new BasicNameValuePair( "name", $name ) ) ;  
  15.         nameValue.add( new BasicNameValuePair( "sex", $sex ) ) ;  
  16.           
  17.         String url = $url + "?" + URLEncodedUtils.format( nameValue, null) ;  
  18.         HttpGet request = new HttpGet( url ) ;  
  19.         return request ;  
  20.     }  
  21. </namevaluepair></namevaluepair></string>  

결과

크리에이티브 커먼즈 라이선스
Trackback Address :: http://androidnote.co.kr/trackback/6  
<form method="post" action="http://androidnote.co.kr/comment/add/6" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">
루밍 | 2010/09/16 00:40 | PERMALINK | EDIT/DEL | REPLY
포스트 잘보고있습니다 ~
따라하면서 궁금한점이 있는데, 웹페이지에 android에서 post방식으로 받은 데이터를 표시해주려면
어떻게해야되나요? 
단순히 print($sex); 이렇게하면 안되는것인지 웹페이지에선 표시가 되질않네요 ㅠㅠ
 AndroidNote | 2010/09/17 07:52 | PERMALINK | EDIT/DEL
질문을 잘 이해하지 못했습니다. POST 방식으로 받은 데이터를 웹페이지에 표현한다는게 어떤 것인지..
테스터 | 2010/10/04 15:05 | PERMALINK | EDIT/DEL | REPLY
질문이 있어서 글올립니다.
한글로 데이터를 넣으면 깨지더라고요
php 에서 혹시 charater-set을 어디서 변경해줘야하는지
안드로이드에서 넘어가는건 utf8으로 되어 있다고 알고있는데...
어떻게 해줘야 좋을까요..ㅠㅠ
몇일 고민하다 올립니다.
 AndroidNote | 2010/10/05 23:18 | PERMALINK | EDIT/DEL
에뮬레이터 말고 기기에서 직접 테스트 한번 해보시면 될것 같아요.
앤드류 | 2010/10/14 13:45 | PERMALINK | EDIT/DEL | REPLY
이것을 JSP에서 하려고 하는데 JSP 에서 값을 받은 다음에 
JSP 에서 값을 보내거나 응답을 어떻게 하고 그 응답을 어플에서는 어떻게 받나여?
몇일을 인터넷을 뒤져도 잘 모르겠네여..;;
감사합니다~
 AndroidNote | 2010/10/15 22:13 | PERMALINK | EDIT/DEL
그야 JSP에서는 어플로부터 받은 요청을 처리해서 XML형식으로 데이터를 만들어 응답하거나 하면 되지 않을까요.

예를들어 위 PHP 같은 경우는 간단하게 어플로부터 받은 요청을 문자열로 응답한것입니다.
존~ | 2010/12/02 00:26 | PERMALINK | EDIT/DEL | REPLY
입력을 영어로하면 잘 입력되고 잘 받는데 한글로 할 경우 글자가 깨지는데 어떻게 해결해야 하나요?
꼭 좀 알려주세요~
오늘도 맑음 | 2010/12/14 17:08 | PERMALINK | EDIT/DEL | REPLY
String result = client.execute( request, reshandler ) ;

이 함수에서 계속 I/O Exception 이 떨어지는 건 왜 그런것일까요?? ㅠㅠ
<input type="text" id="name_6" name="name" value="" class="form_input" style="font: normal normal normal 12px/normal Tahoma; color: rgb(85, 85, 85); margin-top: 4px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 16px; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; height: 18px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(221, 221, 221); border-right-color: rgb(221, 221, 221); border-bottom-color: rgb(221, 221, 221); border-left-color: rgb(221, 221, 221); font-size: 11px; width: 160px; " /> Name
<input type="password" maxlength="8" id="password_6" name="password" value="" class="form_input" style="font: normal normal normal 12px/normal Tahoma; color: rgb(85, 85, 85); margin-top: 4px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 16px; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; height: 18px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(221, 221, 221); border-right-color: rgb(221, 221, 221); border-bottom-color: rgb(221, 221, 221); border-left-color: rgb(221, 221, 221); font-size: 11px; width: 160px; " /> Password 
<input type="text" id="homepage_6" name="homepage" value="http://" class="form_input" style="font: normal normal normal 12px/normal Tahoma; color: rgb(85, 85, 85); margin-top: 4px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 16px; padding-top: 1px; padding-right: 1px; padding-bottom: 1px; padding-left: 1px; height: 18px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(221, 221, 221); border-right-color: rgb(221, 221, 221); border-bottom-color: rgb(221, 221, 221); border-left-color: rgb(221, 221, 221); font-size: 11px; width: 300px; " /> Homepage 
<input type="checkbox" id="secret_6" name="secret" align="absmiddle" style="font: normal normal normal 12px/normal Tahoma; color: rgb(85, 85, 85); margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 18px; " /> Secret
<textarea cols="100%" rows="6" id="comment_6" name="comment" class="form_textarea" style="font: normal normal normal 12px/normal Tahoma; color: rgb(85, 85, 85); margin-top: 4px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: 18px; font-weight: normal; height: 100px; width: 674px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(221, 221, 221); border-right-color: rgb(221, 221, 221); border-bottom-color: rgb(221, 221, 221); border-left-color: rgb(221, 221, 221); overflow-x: visible; overflow-y: visible; clear: both; "></textarea><input type="button" value=" Save a Comment " class="form_submit" style="font: normal normal normal 11px/normal tahoma; color: rgb(68, 68, 68); margin-top: 4px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; line-height: normal; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: rgb(221, 221, 221); border-right-color: rgb(221, 221, 221); border-bottom-color: rgb(221, 221, 221); border-left-color: rgb(221, 221, 221); background-color: rgb(241, 241, 241); height: 25px; width: 674px; cursor: pointer; " />
</form>
 #1 ... #5 #6 #7 #8 #9 #10 #11 #12 #13 ... #14 
YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST