안드로이드에서 JSON 다루기
안드로이드에 포함된 JSON 처리용 클래스를 이용하는 예
웹사이트에서 JSON 문자열을 응답으로 전송하면 안드로이드에서는 JSON 문자열을 수신하여 JSONObject 클래스를 활용하여 파싱하는 내용이다.
org.json.JSONObject 활용
JSP를 이용하여 웹페이지를 다음과 같이 작성한다
JSP에서 JSON 문자열을 생성할 때는 JSON-Simple 자바 라이브러리를 사용했다
해결해야 할 2가지 문제 ( 네트워크 접속 제한, UI 갱신 쓰레드 제한)
메인 쓰레드에서 웹사이트 등 네트워크에 접속할 때는 다음과 같은 오류가 발생한다
android.os.NetworkOnMainThreadException
그러므로 커스텀 쓰레드를 생성하여 네트워크에 접속해야 한다
커스텀 쓰레드에서 화면의 뷰 상태를 변경하려는 경우에는 다음과 같은 오류가 발생한다
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
그러므로 화면의 뷰 상태를 변경하려면 UI 쓰레드를 이용해야 한다
Handler.post(Runnable) 를 사용하면 UI 쓰레드에게 실행할 코드를 전달할 수 있다
runOnUiThread(Runnable)를 사용해도 된다
sample.jsp
<%@page import="org.json.simple.JSONObject"%> <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true"%> <% JSONObject jsObj = new JSONObject(); jsObj.put("num", 100); jsObj.put("title", "JSON Processing test"); jsObj.put("contents", "Sample String"); %> <%=jsObj.toJSONString()%>
안드로이드 측 설정 및 코드
안드로이드 측에서는 웹사이트에 접속해야 하므로 AndroidManifest.xml 파일에 다음과 같은 인터넷 접속 허가 등록을 해야 한다
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.duniv007.helloapp"> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".JSONActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
안드로이드 액티비티 코드
package com.example.duniv007.helloapp; import android.support.v7.app.AppCompatActivity; import android.os.*; import android.util.*; import android.view.*; import android.widget.*; import org.json.*; import java.io.*; import java.net.*; public class JSONActivity extends AppCompatActivity { Button btnConnect; TextView tvNum, tvTitle, tvContents; String jsonStr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_json); tvNum = (TextView) findViewById(R.id.tvNum); tvTitle = (TextView) findViewById(R.id.tvTitle); tvContents = (TextView) findViewById(R.id.tvContents); btnConnect = (Button) findViewById(R.id.btn_connect); btnConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { jsonStr = null; // 메인 쓰레드가 아닌 커스텀 쓰레드에서 네트워크에 접속해야 한다 new Thread() { public void run() { try { URL url = new URL("http://192.168.2.6:8082/JavaWeb/mobile/sample.jsp"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); Log.i("쓰레드", "접속시도"); if (conn != null) { Log.i("쓰레드", "접속성공"); conn.setConnectTimeout(10000); conn.setRequestMethod("GET"); int resCode = conn.getResponseCode(); Log.i("응답코드", ""+resCode); if (resCode == HttpURLConnection.HTTP_OK) { Log.i("쓰레드", "응답수신"); InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); StringBuilder strBuilder = new StringBuilder(); String line = null; while ((line = br.readLine()) != null) { strBuilder.append(line + "\n"); } jsonStr = strBuilder.toString(); br.close(); conn.disconnect(); } Log.i("쓰레드", "응답처리완료"); } }catch (Exception ex){ Log.e("접속요류", ""+ex); } } }.start(); while(jsonStr==null) { try { Thread.sleep(500); }catch (InterruptedException ie){ } } // UI 쓰레드에게 실행할 코드를 전달한다 runOnUiThread(new Runnable() { @Override public void run() { processJSON(jsonStr); } }); } }); } private void processJSON(String jsonStr) { try { JSONObject jsObj = new JSONObject(jsonStr); String sNum = jsObj.getString("num"); String title = jsObj.getString("title"); String contents = jsObj.getString("contents"); tvNum.setText("번 호 : "+sNum); tvTitle.setText("제 목 : "+title); tvContents.setText("내 용 :"+contents); Log.i("num", sNum); Log.i("title", title); Log.i("contents", contents); }catch(Exception ex){ Log.e("JSON", ""+ex); } } }
안드로이드에서 GET 방식으로 파라미터를 전송하고 그 결과를 안드로이드에서 출력하는 예
package com.example.duniv007.helloapp; import android.support.v7.app.AppCompatActivity; import android.os.*; import android.util.*; import android.view.*; import android.widget.*; import org.json.*; import java.io.*; import java.net.*; import java.util.Scanner; public class HttpConnActivity extends AppCompatActivity { Button btnConnect; TextView tvEmpno, tvEname, tvDeptno; String jsonStr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_json); tvEmpno = (TextView) findViewById(R.id.tvEmpno); tvEname = (TextView) findViewById(R.id.tvEname); tvDeptno = (TextView) findViewById(R.id.tvDeptno); btnConnect = (Button) findViewById(R.id.btn_connect); btnConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { jsonStr = null; // 메인 쓰레드가 아닌 커스텀 쓰레드에서 네트워크에 접속해야 한다 new Thread() { public void run() { try { String param = "ename="+URLEncoder.encode("홍길동", "utf-8"); URL url = new URL("http://192.168.2.6:8082/JavaWeb/mobile/getInfoByName.jsp?"+param); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); Log.i("쓰레드", "접속시도"); if (conn != null) { Log.i("쓰레드", "접속성공"); conn.setUseCaches(false); conn.setConnectTimeout(10000); conn.setRequestMethod("GET"); int resCode = conn.getResponseCode(); Log.i("응답코드", ""+resCode); if (resCode == HttpURLConnection.HTTP_OK) { Log.i("쓰레드", "응답수신"); InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); StringBuilder strBuilder = new StringBuilder(); String line = null; while ((line = br.readLine()) != null) { strBuilder.append(line + "\n"); } jsonStr = strBuilder.toString(); br.close(); conn.disconnect(); } Log.i("쓰레드", "응답처리완료"); } }catch (Exception ex){ Log.e("접속요류", ""+ex); } } }.start(); while(jsonStr==null) { try { Thread.sleep(500); }catch (InterruptedException ie){ } } // UI 쓰레드에게 실행할 코드를 전달한다 runOnUiThread(new Runnable() { @Override public void run() { processJSON(jsonStr); } }); } }); } private void processJSON(String jsonStr) { try { JSONObject jsObj = new JSONObject(jsonStr); String empno = jsObj.getString("empno"); String ename = jsObj.getString("ename"); String deptno = jsObj.getString("deptno"); tvEmpno.setText("사 번 : "+empno); tvEname.setText("이 름 : "+ename); tvDeptno.setText("부 서 :"+deptno); }catch(Exception ex){ Log.e("JSON", ""+ex); } } }
위의 안드로이드 코드가 접속하는 서버의 JSP
<%@page import="java.util.Map"%> <%@page import="org.kdea.jdbc.EmpDAO"%> <%@page import="org.json.simple.JSONObject"%> <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true"%> <jsp:useBean id="dao" class="org.kdea.cp.EmpDAO"/> <% String ename = request.getParameter("ename"); System.out.println("파라미터 ename="+ename); Map<String,String> resultMap = dao.getEmpByName(ename); JSONObject jsObj = new JSONObject(); jsObj.put("empno", resultMap.get("empno")); jsObj.put("ename", resultMap.get("ename")); jsObj.put("deptno", resultMap.get("deptno")); %> <%=jsObj.toJSONString()%>
안드로이드에서 POST 방식으로 요청하고 그 결과를 안드로이드에서 출력하는 예
( 서버로 데이터 전송시 out.write ( "ename=홍길동".getBytes("utf-8") ) 사용 )
package com.example.duniv007.helloapp; import android.support.v7.app.AppCompatActivity; import android.os.*; import android.util.*; import android.view.*; import android.widget.*; import org.json.*; import java.io.*; import java.net.*; import java.util.Scanner; public class HttpConnActivity extends AppCompatActivity { Button btnConnect; TextView tvEmpno, tvEname, tvDeptno; String jsonStr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_json); tvEmpno = (TextView) findViewById(R.id.tvEmpno); tvEname = (TextView) findViewById(R.id.tvEname); tvDeptno = (TextView) findViewById(R.id.tvDeptno); btnConnect = (Button) findViewById(R.id.btn_connect); btnConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { jsonStr = null; // 메인 쓰레드가 아닌 커스텀 쓰레드에서 네트워크에 접속해야 한다 new Thread() { public void run() { try { URL url = new URL("http://192.168.2.6:8082/JavaWeb/mobile/getInfoByName.jsp"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); Log.i("쓰레드", "접속시도"); if (conn != null) { Log.i("쓰레드", "접속성공"); conn.setUseCaches(false); conn.setConnectTimeout(10000); conn.setRequestMethod("POST"); conn.setDoInput(true); // 서버로부터 입력을 받도록 설정 conn.setDoOutput(true); // 서버로 출력할 수 있게 설정, 자동으로 POST 방식이 됨 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); OutputStream out = conn.getOutputStream(); out.write("ename=홍길동".getBytes("utf-8")); out.flush(); int resCode = conn.getResponseCode(); Log.i("응답코드", ""+resCode); if (resCode == HttpURLConnection.HTTP_OK) { Log.i("쓰레드", "응답수신"); InputStream is = conn.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); StringBuilder strBuilder = new StringBuilder(); String line = null; while ((line = br.readLine()) != null) { strBuilder.append(line + "\n"); } jsonStr = strBuilder.toString(); br.close(); conn.disconnect(); } Log.i("쓰레드", "응답처리완료"); } }catch (Exception ex){ Log.e("접속요류", ""+ex); } } }.start(); while(jsonStr==null) { try { Thread.sleep(500); }catch (InterruptedException ie){ } } // UI 쓰레드에게 실행할 코드를 전달한다 runOnUiThread(new Runnable() { @Override public void run() { processJSON(jsonStr); } }); } }); } private void processJSON(String jsonStr) { try { JSONObject jsObj = new JSONObject(jsonStr); String empno = jsObj.getString("empno"); String ename = jsObj.getString("ename"); String deptno = jsObj.getString("deptno"); tvEmpno.setText("사 번 : "+empno); tvEname.setText("이 름 : "+ename); tvDeptno.setText("부 서 :"+deptno); }catch(Exception ex){ Log.e("JSON", ""+ex); } } }
위의 안드로이드 코드가 접속하는 서버의 JSP
( request.setCharacterEncoding("utf-8") 사용 )
<%@page import="java.util.Map"%> <%@page import="org.kdea.jdbc.EmpDAO"%> <%@page import="org.json.simple.JSONObject"%> <%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" trimDirectiveWhitespaces="true"%> <jsp:useBean id="dao" class="org.kdea.cp.EmpDAO"/> <% request.setCharacterEncoding("utf-8"); String ename = request.getParameter("ename"); System.out.println("파라미터 ename="+ename); Map<String,String> resultMap = dao.getEmpByName(ename); JSONObject jsObj = new JSONObject(); jsObj.put("empno", resultMap.get("empno")); jsObj.put("ename", resultMap.get("ename")); jsObj.put("deptno", resultMap.get("deptno")); %> <%=jsObj.toJSONString()%>