안드로이드와 mysql 연동시키는 방법은 상당히 복잡합니다. 왜냐하면, 안드로이드에서 직접 mysql DB에 접속하는 것을 막아놨기 때문입니다. 보안상 막았다고 하는데....
안드로이드에서 바로 접속할 수 없어서 웹을 거쳐서 DB에 접속해야 합니다. 이때 웹이란 PHP 나 JSP 같은 웹 프로그래밍언어를 사용합니다. PHP가 간단하고 쉬워서 PHP를 사용하겠습니다.
방법은 "안드로이드(자바) <-> PHP <-> SQL" 입니다.
일단 phpMyAdmin 을 이용해 mysql 에 테이블을 만듭니다. 저는 이미지의 주소 값과 텍스트 두 개가 필요해서 총 3개의 텍스트 필드를 가진 테이블을 만들었습니다.
데이터베이스의 이름은 appdata 이고 테이블 이름은 urltext 입니다. 데이터베이스에 접속하기 위해서는 꼭 필요하니 기억해 둡시다.
이제 PHP 파일을 봅니다. PHP 파일은 sql 쿼리별로 여러개를 만들어야 합니다. 일단 데이터베이스에 있는 모든 자료를 가져오는 PHP 코드를 만듭니다.
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 | <? // 데이터베이스 접속 문자열. (db위치, 유저 이름, 비밀번호) $connect=mysql_connect( "MYSQL주소", "아이디", "비밀번호") or die( "SQL server에 연결할 수 없습니다."); mysql_query("SET NAMES UTF8"); // 데이터베이스 선택 mysql_select_db("appdata",$connect); // 세션 시작 session_start(); // 쿼리문 생성 $sql = "select * from urltext"; // 쿼리 실행 결과를 $result에 저장 $result = mysql_query($sql, $connect); // 반환된 전체 레코드 수 저장. $total_record = mysql_num_rows($result); // JSONArray 형식으로 만들기 위해서... echo "{\"status\":\"OK\",\"num_results\":\"$total_record\",\"results\":["; // 반환된 각 레코드별로 JSONArray 형식으로 만들기. for ($i=0; $i < $total_record; $i++) { // 가져올 레코드로 위치(포인터) 이동 mysql_data_seek($result, $i); $row = mysql_fetch_array($result); echo "{\"imgurl\":$row[imgurl],\"txt1\":\"$row[txt1]\",\"txt2\":\"$row[txt2]\"}"; // 마지막 레코드 이전엔 ,를 붙인다. 그래야 데이터 구분이 되니깐. if($i<$total_record-1){ echo ","; } } // JSONArray의 마지막 닫기 echo "]}"; ?> |
위와 같이 PHP 파일은 만들어서 웹 서버에 올립니다. 저는 파일 이름을 appdata.php 라고 정하고 서버에 올렸습니다.
PHP 파일을 보면 15번째 줄에 $sql = "select * from urltext" 가 바로 쿼리입니다. 테이블의 모든 정보를 가져오기 위해 select * 라는 쿼리문을 사용했습니다. 쿼리의 결과를 Json 파일로 만들기 위해 23번째 줄의 코드를 입력합니다. Json 파일의 헤더와 같은 역할입니다. 실질적인 데이터는 for 문을 사용해 테이블에 있는 자료를 레코드단위로 불러옵니다. 완전히 출력된 Json 문장이 어떤 형태인지 좀 있다 확인해 보겠습니다.
데이터베이스에 접속하는 PHP 문서를 만들었습니다. 이제 안드로이드 상에서 이 PHP 파일을 읽기만 하면 됩니다. PHP 파일 역시 웹상에 있기 때문에 웹에 접속하는 코드를 사용해야 합니다. 즉, 메인 쓰레드에서 실행시키면 실행이 안 된다는 것이지요. 옛날엔 그냥 됬는데 쩝....
아무튼, 또 귀찮게 asynctask를 사용합니다. 두 세 번 사용해보니 이젠 쉽게 사용할 수 있게 되었습니다.
다음은 PHP에서 Json파일이 잘 만들어지는지 확인해보기 위한 코드입니다.
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | package com.example.downloadimg; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { ImageView imView; TextView txtView; String imgUrl = "http://서버주소/appimg/"; Bitmap bmImg; //back task; phpDown task; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); task = new phpDown(); txtView = (TextView)findViewById(R.id.txtView); //imView = (ImageView) findViewById(R.id.imageView1); task.execute("http://서버주소/appdata.php"); } private class back extends AsyncTask<String, Integer,Bitmap>{ @Override protected Bitmap doInBackground(String... urls) { // TODO Auto-generated method stub try{ URL myFileUrl = new URL(urls[0]); HttpURLConnection conn = (HttpURLConnection)myFileUrl.openConnection(); conn.setDoInput(true); conn.connect(); //String json = DownloadHtml("http://서버주소/appdata.php"); InputStream is = conn.getInputStream(); bmImg = BitmapFactory.decodeStream(is); }catch(IOException e){ e.printStackTrace(); } return bmImg; } protected void onPostExecute(Bitmap img){ imView.setImageBitmap(bmImg); } } private class phpDown extends AsyncTask<String, Integer,String>{ @Override protected String doInBackground(String... urls) { StringBuilder jsonHtml = new StringBuilder(); try{ // 연결 url 설정 URL url = new URL(urls[0]); // 커넥션 객체 생성 HttpURLConnection conn = (HttpURLConnection)url.openConnection(); // 연결되었으면. if(conn != null){ conn.setConnectTimeout(10000); conn.setUseCaches(false); // 연결되었음 코드가 리턴되면. if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){ BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); for(;;){ // 웹상에 보여지는 텍스트를 라인단위로 읽어 저장. String line = br.readLine(); if(line == null) break; // 저장된 텍스트 라인을 jsonHtml에 붙여넣음 jsonHtml.append(line + "\n"); } br.close(); } conn.disconnect(); } } catch(Exception ex){ ex.printStackTrace(); } return jsonHtml.toString(); } protected void onPostExecute(String str){ txtView.setText(str); } } } |
지난 시간에 했던 서버에서 이미지를 불러오는 코드와 같이했더니 코드가 깁니다. 주석으로 처리한 부분은 삭제해도 됩니다.
phpDown 이라는 AsyncTask 를 이용해 웹에 있는 php 파일을 읽습니다. php 파일을 읽고 나면 결과로 스트링을 반환하는데 이것이 Json 형식의 문서입니다. 바로 텍스트뷰에 띄워보면 다음과 같이 출력됩니다.
이것이 Json 형식입니다. 원래는 한 칸 띄기가 들어가서 보기 좋게 쓰는게 정석인데... 어차피 사용자에게 보일 문서가 아니기에 그냥 다 붙여서 써도 상관없습니다. 형식만 맞는다면 상관없어요~
이제 남은 건 DB에서 Json 형식으로 뽑아온 자료를 안드로이드에서 사용할 수 있도록 변수에 집어넣는 것 입니다.
일단 스트링 형식의 데이터를 3개 저장할 수 있는 객체를 만듭니다.
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 | package com.example.downloadimg; public class ListItem { private String[] mData; public ListItem(String[] data ){ mData = data; } public ListItem(String imgurl, String txt1, String txt2){ mData = new String[3]; mData[0] = imgurl; mData[1] = txt1; mData[2] = txt2; } public String[] getData(){ return mData; } public String getData(int index){ return mData[index]; } public void setData(String[] data){ mData = data; } } |
그리고 이 객체를 ArrayList로 만들어서 Json에 있는 데이터를 하나씩 넣어주면 끗.
일줄 알았는데 생각보다 복잡하네요... 끙끙대다가 겨우 완성했습니다.
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | package com.example.downloadimg; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; public class MainActivity extends Activity { ImageView imView; TextView txtView; String imgUrl = "http://dnllab.incheon.ac.kr/appimg/"; Bitmap bmImg; //back task; phpDown task; ArrayList<ListItem> listItem= new ArrayList<ListItem>(); ListItem Item; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); task = new phpDown(); txtView = (TextView)findViewById(R.id.txtView); //imView = (ImageView) findViewById(R.id.imageView1); task.execute("http://dnllab.incheon.ac.kr/appdata1.php"); } private class back extends AsyncTask<String, Integer,Bitmap>{ @Override protected Bitmap doInBackground(String... urls) { // TODO Auto-generated method stub try{ URL myFileUrl = new URL(urls[0]); HttpURLConnection conn = (HttpURLConnection)myFileUrl.openConnection(); conn.setDoInput(true); conn.connect(); //String json = DownloadHtml("http://117.16.243.116/appdata.php"); InputStream is = conn.getInputStream(); bmImg = BitmapFactory.decodeStream(is); }catch(IOException e){ e.printStackTrace(); } return bmImg; } protected void onPostExecute(Bitmap img){ imView.setImageBitmap(bmImg); } } private class phpDown extends AsyncTask<String, Integer,String>{ @Override protected String doInBackground(String... urls) { StringBuilder jsonHtml = new StringBuilder(); try{ // 연결 url 설정 URL url = new URL(urls[0]); // 커넥션 객체 생성 HttpURLConnection conn = (HttpURLConnection)url.openConnection(); // 연결되었으면. if(conn != null){ conn.setConnectTimeout(10000); conn.setUseCaches(false); // 연결되었음 코드가 리턴되면. if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){ BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); for(;;){ // 웹상에 보여지는 텍스트를 라인단위로 읽어 저장. String line = br.readLine(); if(line == null) break; // 저장된 텍스트 라인을 jsonHtml에 붙여넣음 jsonHtml.append(line + "\n"); } br.close(); } conn.disconnect(); } } catch(Exception ex){ ex.printStackTrace(); } return jsonHtml.toString(); } protected void onPostExecute(String str){ String imgurl; String txt1; String txt2; try{ JSONObject root = new JSONObject(str); JSONArray ja = root.getJSONArray("results"); for(int i=0; i<ja.length(); i++){ JSONObject jo = ja.getJSONObject(i); imgurl = jo.getString("imgurl"); txt1 = jo.getString("txt1"); txt2 = jo.getString("txt2"); listItem.add(new ListItem(imgurl,txt1,txt2)); } }catch(JSONException e){ e.printStackTrace(); } txtView.setText("urlimg :"+listItem.get(0).getData(0)+"\ntxt1:"+ listItem.get(0).getData(1)+"\ntxt2:"+listItem.get(0).getData(2)); } } } |
118번째 줄부터 보시면 됩니다.
아까 그냥 보여줬던 String을 이번에는 JSONObject 라는 객체에 넣습니다.
JSONObject root = new JSONObject(str); JSONArray ja = root.getJSONArray("results"); |
위 두 줄의 코드가 핵심입니다. Json 문서를 JSONObject 객체로 받은 뒤, JSONArray 를 선언합니다. 이때 JSONObject 에서 JSONArray 를 get 해오는데, results라는 것은 제 Json 문서의 결과 값 리스트입니다. 위를 보시면 제 Json 문서는 이런 식 입니다.
{ "status": "OK", "num_results": “3”, "results": [ {자료1}, {자료2}, {자료3}... ] } |
자료들의 리스트를 "results" 라고 정의했습니다. 그래서 저는 "results" 라고 적었습니다. 사용자가 정의할 수 있기 때문에 Json 문서를 잘 보시고 입력해야 합니다.
아래의 for문은 간단합니다. Json 에서 해당 자료의 데이터를 뽑아오는 것인데 저는 "imgurl", "txt1", "txt2" 라는 값이 있기 때문에 3가지 스트링값을 받아왔습니다. 그리고 아까 만든 ListItem 객체로 만들어서 ListItem ArrayList 에 추가합니다.
잘 추가가 되었는지 하나만 출력해보기 위해 txtView.setText 메소드를 사용해 출력해 보았습니다.