안드로이드에서 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()%>