본문 바로가기

Android Studio/JSON

JSON in Android

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