ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Android PHP MySQL 예제 - 데이터베이스에 데이터 저장 및 JSON 형식으로 가져오는 예제 프로젝트
    Android/Android PHP MySQL 예제 2019. 11. 17. 19:15




    데이터베이스에 데이터를 입력하고 JSON 형식으로 데이터를 가져오는 예제입니다. 

    검색 결과를 가져올 수도 있습니다.



    다음 세 개의 포스팅에 있는 코드를 하나의 앱에서 동작하도록 수정한 결과입니다.

    나라만 검색하다록 query.php를 수정하였고  안드로이드 코드는 RecyclerView를 사용합니다.



    최초 작성 - 2018.   6. 17

                       2018.   6. 27 -  ListVIew를 RecyclerView로 변경.

                       2019. 11.  17 - androidx 사용하도록 변경





    1. 동작 설명


    2. 전체 소스코드 및 사용방법


    3. 관련 포스팅


    4. 참고






    1. 동작 설명


    이름, 나라 항목에 데이터를 입력하고 입력 버튼을 터치하면 데이터베이스에 데이터가 저장됩니다. 


     




    전체 버튼을 클릭하면 입력되어 있는 모든 데이터를 보여줍니다. 





    검색할 나라를 입력하고 검색 버튼을 클릭하면 해당 데이터만 보여줍니다.


     




    2. 전체 소스코드 및 사용방법

    RecyclerView를 사용하려면  build.gradle에 다음 노란줄을 추가해야 합니다. 


    dependencies {

        implementation fileTree(dir: 'libs', include: ['*.jar'])

        implementation 'androidx.appcompat:appcompat:1.0.2'

        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

        implementation 'androidx.recyclerview:recyclerview:1.0.0'

        testImplementation 'junit:junit:4.12'

        androidTestImplementation 'androidx.test.ext:junit:1.1.0'

        androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    }



    2-1. 데이터베이스 및 테이블 생성

    MySQL에서 데이터베이스 및 테이블을 생성합니다.


    create database testdb DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

    use testdb;

    create table Person(
        id bigint(20) unsigned not null auto_increment,
        name varchar(255) not null,
        country varchar(255) not null,
        primary key (id)
    ) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;



    2-2. PHP 코드

    php 파일은 우분투라면 /var/www/html 위치에, 윈도우에서 wamp를 사용한다면  C:\wamp\www 위치에 파일들을 생성합니다.


    dbcon.php


    <?php

        $host = 'localhost';
        $username = 'webnautes'; # MySQL 계정 아이디
        $password = 'apple9!'; # MySQL 계정 패스워드
        $dbname = 'testdb'# DATABASE 이름


        $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
       
        try {

            $con = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8",$username, $password);
        } catch(PDOException $e) {

            die("Failed to connect to the database: " . $e->getMessage());
        }


        $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
            function undo_magic_quotes_gpc(&$array) {
                foreach($array as &$value) {
                    if(is_array($value)) {
                        undo_magic_quotes_gpc($value);
                    }
                    else {
                        $value = stripslashes($value);
                    }
                }
            }

            undo_magic_quotes_gpc($_POST);
            undo_magic_quotes_gpc($_GET);
            undo_magic_quotes_gpc($_COOKIE);
        }

        header('Content-Type: text/html; charset=utf-8');
        #session_start();
    ?>


    insert.php


    안드로이드 앱에서 POST 방식으로 전송한 데이터를 받아서 데이터베이스의 테이블에 저장합니다.


    <?php

        error_reporting(E_ALL);
        ini_set('display_errors',1);

        include('dbcon.php');


        $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");


        if( (($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit'])) || $android )
        {

            // 안드로이드 코드의 postParameters 변수에 적어준 이름을 가지고 값을 전달 받습니다.

            $name=$_POST['name'];
            $country=$_POST['country'];

            if(empty($name)){
                $errMSG = "이름을 입력하세요.";
            }
            else if(empty($country)){
                $errMSG = "나라를 입력하세요.";
            }

            if(!isset($errMSG)) // 이름과 나라 모두 입력이 되었다면
            {
                try{
                    // SQL문을 실행하여 데이터를 MySQL 서버의 person 테이블에 저장합니다.
                    $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                    $stmt->bindParam(':name', $name);
                    $stmt->bindParam(':country', $country);

                    if($stmt->execute())
                    {
                        $successMSG = "새로운 사용자를 추가했습니다.";
                    }
                    else
                    {
                        $errMSG = "사용자 추가 에러";
                    }

                } catch(PDOException $e) {
                    die("Database error: " . $e->getMessage());
                }
            }

        }

    ?>


    <?php
        if (isset($errMSG)) echo $errMSG;
        if (isset($successMSG)) echo $successMSG;

    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");
     
        if( !$android )
        {
    ?>
        <html>
          <body>

                <form action="<?php $_PHP_SELF ?>" method="POST">
                    Name: <input type = "text" name = "name" />
                    Country: <input type = "text" name = "country" />
                    <input type = "submit" name = "submit" />
                </form>
         
          </body>
        </html>

    <?php
        }
    ?>




    getjson.php

    데이터베이스의 테이블에 있는 모든 데이터를 안드로이드 앱으로 가져오기 위해서 사용됩니다. 


    <?php

        error_reporting(E_ALL);
        ini_set('display_errors',1);

        include('dbcon.php');
           

        $stmt = $con->prepare('select * from person');
        $stmt->execute();

        if ($stmt->rowCount() > 0)
        {
            $data = array();

            while($row=$stmt->fetch(PDO::FETCH_ASSOC))
            {
                extract($row);
       
                array_push($data,
                    array('id'=>$id,
                    'name'=>$name,
                    'country'=>$country
                ));
            }

            header('Content-Type: application/json; charset=utf8');
            $json = json_encode(array("webnautes"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
            echo $json;
        }

    ?>



    query.php

    안드로이드 앱에서 입력한 나라 이름에 대응하는 레코드만 조회하여  안드로이드앱으로 리턴하기 위해서 사용됩니다.  


    <?php 
    error_reporting(E_ALL);
    ini_set('display_errors',1);

    include('dbcon.php');



    //POST 값을 읽어온다.
    $country=isset($_POST['country']) ? $_POST['country'] : '';
    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");


    if ($country != "" ){

        $sql="select * from person where country='$country'";
        $stmt = $con->prepare($sql);
        $stmt->execute();

        if ($stmt->rowCount() == 0){

            echo "'";
            echo $country;
            echo "'은 찾을 수 없습니다.";
        }
    else{

      $data = array();

            while($row=$stmt->fetch(PDO::FETCH_ASSOC)){

            extract($row);

                array_push($data,
                    array('id'=>$row["id"],
                    'name'=>$row["name"],
                    'country'=>$row["country"]
                ));
            }


            if (!$android) {
                echo "<pre>";
                print_r($data);
                echo '</pre>';
            }else
            {
                header('Content-Type: application/json; charset=utf8');
                $json = json_encode(array("webnautes"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);
                echo $json;
            }
        }
    }
    else {
        echo "검색할 나라를 입력하세요 ";
    }

    ?>



    <?php

    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");

    if (!$android){
    ?>

    <html>
      <body>
     
          <form action="<?php $_PHP_SELF ?>" method="POST">
            나라 이름: <input type = "text" name = "country" />
            <input type = "submit" />
          </form>
     
      </body>
    </html>
    <?php
    }

     
    ?>





    2-3. 안드로이드 XML 코드

    AndroidManifest.xml 

    인터넷 사용 권한을 추가합니다.


    android 9.0 이상에서 동작하게 하려면 usesCleartextTraffic 옵션도 추가해야 합니다. 해주지 않으면 “cleartext http traffic to not permitted” 라는 에러가 발생합니다.  



    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.tistory.webnautes.phptest">

        <uses-permission android:name="android.permission.INTERNET" />

        <application
            android:usesCleartextTraffic="true"
            android:allowBackup="true"



    styles.xml 


    다음 두 줄을 추가하여 타이틀 바를 보이지않게 합니다.


    <resources>

        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <!-- 타이틀바 제거 -->
           <item name="windowActionBar">false</item>
            <item name="windowNoTitle">true</item>
        </style>

    </resources>




    activity_main.xml

    디폴트 액티비티인 MainActivity의 사용자 인터페이스(UI)로 사용되는 레이아웃 파일입니다. 


    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:padding="10dp">


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="8.5"
            android:orientation="vertical">

        <TextView
            android:layout_marginBottom="5dp"
            android:text="이름과 나라를 입력 후 입력 버튼을 터치하세요."
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView_main_input" />

        <EditText
            android:layout_margin="5dp"
            android:hint = "이름을 입력하세요."
            android:inputType="text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/editText_main_name" />

        <EditText
            android:layout_margin="5dp"
            android:hint = "나라를 입력하세요."
            android:inputType="text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/editText_main_country" />

        <Button
            android:layout_margin="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="입력"
            android:id="@+id/button_main_insert" />

        <TextView
            android:layout_marginTop="20dp"
            android:layout_marginBottom="5dp"
            android:text="나라 이름을 입력 후 검색 버튼을 터치하세요."
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView_main_search" />

        <LinearLayout
            android:layout_margin="5dp"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:orientation="horizontal">

            <EditText
                android:layout_margin="2dp"
                android:hint = "검색할 나라를 입력하세요"
                android:inputType="text"
                android:id="@+id/editText_main_searchKeyword"
                android:layout_width="0dp"
                android:layout_weight="0.7"
                android:layout_height="wrap_content" />

            <Button
                android:layout_margin="2dp"
                android:id="@+id/button_main_search"
                android:layout_width="0dp"
                android:layout_weight="0.3"
                android:layout_height="wrap_content"
                android:text="검색" />

            <Button
                android:layout_margin="2dp"
                android:id="@+id/button_main_all"
                android:layout_width="0dp"
                android:layout_weight="0.3"
                android:layout_height="wrap_content"
                android:text="전체보기" />

        </LinearLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:layout_margin="5dp"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="6"
            android:id="@+id/listView_main_list" />


        <!--- 디버깅 용 -->
        <TextView
            android:layout_marginTop="20dp"
            android:layout_marginBottom="5dp"
            android:text="디버깅 용"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView_main_debug" />

        <TextView
            android:layout_margin="5dp"
            android:id="@+id/textView_main_result"
            android:scrollbars = "vertical"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1.5" />
        </LinearLayout>


    </LinearLayout>



    데이터 입력,  데이터 조회, 디버깅용 정보 출력으로 구성됩니다. 




    item_list.xml

    layout 폴더에 추가합니다.

    RecyclerView의 한 줄에 세 개의 컬럼을 만들기 위해 사용됩니다. 


    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:layout_margin="5dp"
        android:padding="5dp">

        <TextView
            android:id="@+id/textView_list_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:padding="5dp" />


        <TextView
            android:id="@+id/textView_list_name"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
                    android:layout_margin="5dp"
            android:padding="5dp" />


        <TextView
            android:id="@+id/textView_list_address"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:padding="5dp" />

    </LinearLayout>






    2-4. 안드로이드 앱 자바코드

    자바코드들은 똑같은 패키지 이름이 첫줄에 명시되어 있어야 합니다. 

    포스팅에서는 다음과 같은 패키지 이름을 사용합니다.


    package com.tistory.webnautes.phpexample;



    PersonalData.java


    package com.tistory.webnautes.phpexample;


    public class PersonalData {
        private String member_id;
        private String member_name;
        private String member_address;

        public String getMember_id() {
            return member_id;
        }

        public String getMember_name() {
            return member_name;
        }

        public String getMember_address() {
            return member_address;
        }

        public void setMember_id(String member_id) {
            this.member_id = member_id;
        }

        public void setMember_name(String member_name) {
            this.member_name = member_name;
        }

        public void setMember_address(String member_address) {
            this.member_address = member_address;
        }
    }




    UsersAdapter.java

    ArrayList에 있는 PersonalData 타입의 데이터를 RecyclerView에 보여주는 작업을 합니다. 


    package com.tistory.webnautes.phpexample;


    import android.app.Activity;
    import androidx.annotation.NonNull;
    import androidx.recyclerview.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;

    import java.util.ArrayList;


    public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.CustomViewHolder> {

        private ArrayList<PersonalData> mList = null;
        private Activity context = null;


        public UsersAdapter(Activity context, ArrayList<PersonalData> list) {
            this.context = context;
            this.mList = list;
        }

        class CustomViewHolder extends RecyclerView.ViewHolder {
            protected TextView id;
            protected TextView name;
            protected TextView address;


            public CustomViewHolder(View view) {
                super(view);
                this.id = (TextView) view.findViewById(R.id.textView_list_id);
                this.name = (TextView) view.findViewById(R.id.textView_list_name);
                this.address = (TextView) view.findViewById(R.id.textView_list_address);
            }
        }


        @Override
        public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_list, null);
            CustomViewHolder viewHolder = new CustomViewHolder(view);

            return viewHolder;
        }

        @Override
        public void onBindViewHolder(@NonNull CustomViewHolder viewholder, int position) {

            viewholder.id.setText(mList.get(position).getMember_id());
            viewholder.name.setText(mList.get(position).getMember_name());
            viewholder.address.setText(mList.get(position).getMember_address());
        }

        @Override
        public int getItemCount() {
            return (null != mList ? mList.size() : 0);
        }

    }




    MainActivity.java


    다음 줄에 있는 IP 주소를 MySQL 서버가 설치된  컴퓨터의 IP로 수정하세요.


        private static String IP_ADDRESS = "IP_ADDRESS";


    package com.tistory.webnautes.phpexample;

    import android.app.ProgressDialog;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.recyclerview.widget.LinearLayoutManager;
    import androidx.recyclerview.widget.RecyclerView;
    import android.text.method.ScrollingMovementMethod;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;


    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;

    import java.io.BufferedReader;

    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;

    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.ArrayList;


    public class MainActivity extends AppCompatActivity {

        private static String IP_ADDRESS = "IP_ADDRESS";
        private static String TAG = "phpexample";

        private EditText mEditTextName;
        private EditText mEditTextCountry;
        private TextView mTextViewResult;
        private ArrayList<PersonalData> mArrayList;
        private UsersAdapter mAdapter;
        private RecyclerView mRecyclerView;
        private EditText mEditTextSearchKeyword;
        private String mJsonString;


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            mEditTextName = (EditText)findViewById(R.id.editText_main_name);
            mEditTextCountry = (EditText)findViewById(R.id.editText_main_country);
            mTextViewResult = (TextView)findViewById(R.id.textView_main_result);
            mRecyclerView = (RecyclerView) findViewById(R.id.listView_main_list);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

            mEditTextSearchKeyword = (EditText) findViewById(R.id.editText_main_searchKeyword);

            mTextViewResult.setMovementMethod(new ScrollingMovementMethod());



            mArrayList = new ArrayList<>();

            mAdapter = new UsersAdapter(this, mArrayList);
            mRecyclerView.setAdapter(mAdapter);


            Button buttonInsert = (Button)findViewById(R.id.button_main_insert);
            buttonInsert.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    String name = mEditTextName.getText().toString();
                    String country = mEditTextCountry.getText().toString();

                    InsertData task = new InsertData();
                    task.execute("http://" + IP_ADDRESS + "/insert.php", name,country);


                    mEditTextName.setText("");
                    mEditTextCountry.setText("");

                }
            });


            Button button_search = (Button) findViewById(R.id.button_main_search);
            button_search.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {

                    mArrayList.clear();
                    mAdapter.notifyDataSetChanged();


                    String Keyword =  mEditTextSearchKeyword.getText().toString();
                    mEditTextSearchKeyword.setText("");

                    GetData task = new GetData();
                    task.execute( "http://" + IP_ADDRESS + "/query.php", Keyword);
                }
            });


            Button button_all = (Button) findViewById(R.id.button_main_all);
            button_all.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {

                    mArrayList.clear();
                    mAdapter.notifyDataSetChanged();

                    GetData task = new GetData();
                    task.execute( "http://" + IP_ADDRESS + "/getjson.php", "");
                }
            });

        }


        class InsertData extends AsyncTask<String, Void, String>{
            ProgressDialog progressDialog;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();

                progressDialog = ProgressDialog.show(MainActivity.this,
                        "Please Wait", null, true, true);
            }


            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);

                progressDialog.dismiss();
                mTextViewResult.setText(result);
                Log.d(TAG, "POST response  - " + result);
            }


            @Override
            protected String doInBackground(String... params) {

                String name = (String)params[1];
                String country = (String)params[2];

                String serverURL = (String)params[0];
                String postParameters = "name=" + name + "&country=" + country;


                try {

                    URL url = new URL(serverURL);
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();


                    httpURLConnection.setReadTimeout(5000);
                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setRequestMethod("POST");
                    httpURLConnection.connect();


                    OutputStream outputStream = httpURLConnection.getOutputStream();
                    outputStream.write(postParameters.getBytes("UTF-8"));
                    outputStream.flush();
                    outputStream.close();


                    int responseStatusCode = httpURLConnection.getResponseCode();
                    Log.d(TAG, "POST response code - " + responseStatusCode);

                    InputStream inputStream;
                    if(responseStatusCode == HttpURLConnection.HTTP_OK) {
                        inputStream = httpURLConnection.getInputStream();
                    }
                    else{
                        inputStream = httpURLConnection.getErrorStream();
                    }


                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

                    StringBuilder sb = new StringBuilder();
                    String line = null;

                    while((line = bufferedReader.readLine()) != null){
                        sb.append(line);
                    }


                    bufferedReader.close();


                    return sb.toString();


                } catch (Exception e) {

                    Log.d(TAG, "InsertData: Error ", e);

                    return new String("Error: " + e.getMessage());
                }

            }
        }


        private class GetData extends AsyncTask<String, Void, String>{

            ProgressDialog progressDialog;
            String errorString = null;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();

                progressDialog = ProgressDialog.show(MainActivity.this,
                        "Please Wait", null, true, true);
            }


            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);

                progressDialog.dismiss();
                mTextViewResult.setText(result);
                Log.d(TAG, "response - " + result);

                if (result == null){

                    mTextViewResult.setText(errorString);
                }
                else {

                    mJsonString = result;
                    showResult();
                }
            }


            @Override
            protected String doInBackground(String... params) {

                String serverURL = params[0];
                String postParameters = "country=" + params[1];


                try {

                    URL url = new URL(serverURL);
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();


                    httpURLConnection.setReadTimeout(5000);
                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setRequestMethod("POST");
                    httpURLConnection.setDoInput(true);
                    httpURLConnection.connect();


                    OutputStream outputStream = httpURLConnection.getOutputStream();
                    outputStream.write(postParameters.getBytes("UTF-8"));
                    outputStream.flush();
                    outputStream.close();


                    int responseStatusCode = httpURLConnection.getResponseCode();
                    Log.d(TAG, "response code - " + responseStatusCode);

                    InputStream inputStream;
                    if(responseStatusCode == HttpURLConnection.HTTP_OK) {
                        inputStream = httpURLConnection.getInputStream();
                    }
                    else{
                        inputStream = httpURLConnection.getErrorStream();
                    }


                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

                    StringBuilder sb = new StringBuilder();
                    String line;

                    while((line = bufferedReader.readLine()) != null){
                        sb.append(line);
                    }

                    bufferedReader.close();

                    return sb.toString().trim();


                } catch (Exception e) {

                    Log.d(TAG, "InsertData: Error ", e);
                    errorString = e.toString();

                    return null;
                }

            }
        }


        private void showResult(){

            String TAG_JSON="webnautes";
            String TAG_ID = "id";
            String TAG_NAME = "name";
            String TAG_COUNTRY ="country";


            try {
                JSONObject jsonObject = new JSONObject(mJsonString);
                JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);

                for(int i=0;i<jsonArray.length();i++){

                    JSONObject item = jsonArray.getJSONObject(i);

                    String id = item.getString(TAG_ID);
                    String name = item.getString(TAG_NAME);
                    String address = item.getString(TAG_COUNTRY);

                    PersonalData personalData = new PersonalData();

                    personalData.setMember_id(id);
                    personalData.setMember_name(name);
                    personalData.setMember_address(address);

                    mArrayList.add(personalData);
                    mAdapter.notifyDataSetChanged();
                }



            } catch (JSONException e) {

                Log.d(TAG, "showResult : ", e);
            }

        }

    }



    3. 관련 포스팅



    Android PHP MySQL 예제 - 데이터베이스에 데이터 입력하기

    http://webnautes.tistory.com/828 


    Android PHP MySQL 예제 - 데이터베이스에서 데이터를 JSON 형식으로 가져오기

    http://webnautes.tistory.com/829


    Android PHP MySQL 예제 - 데이터베이스 질의(query) 결과 출력하기

    https://webnautes.tistory.com/1159




    4. 참고


    [1] https://developer.android.com/guide/topics/ui/layout/recyclerview


    [2] http://stacktips.com/tutorials/android/android-recyclerview-example




    포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
    댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

    여러분의 응원으로 좋은 컨텐츠가 만들어집니다. 지금 본 내용이 도움이 되었다면 후원 또는 유튜브 구독 부탁드립니다. 감사합니다 : )

    유튜브 구 독 하 기
    후 원 하 기


    댓글 79

    • Malpic 2018.09.07 15:18


      안드로이드쪽에서 계속 문제가 있다면서 열리지를 않습니다.
      그래서 실제로 http:// 제 아이피/php 문서를 일일이 들어가 봤는데
      getjson을 제외하고 나머지는 밑에 원래 보이던 입력창이 없어졌습니다.
      어떻게 해결해야하나요

    • lioba 2018.10.23 23:21


      안녕하세요
      jsonObject = new JSONObject(mJsonString); 이부분에 대해서
      D/bbbb: showResult :
      org.json.JSONException: Value Notice of type java.lang.String cannot be converted to JSONObject
      이런 오류가 뜨는데 어떻게 해결해야 하나요? query.php 파일도 위에 설명하신 그대로 json_encode로 했고 어떻게 해야할지...

    • 1 2018.11.13 11:59


      Value of type java.lang.String cannot be converted to JSONObject 로
      디버깅에는 제이슨이 바르게 표기되는데

      listView_main_list에는 안나오는 현상
      어떻게 해결해야 할까요?
      쓰레기값이 들어가나....

    • Favicon of http://www.facebook.com/appsu123 BlogIcon Won 2018.11.26 22:57


      안녕하세요 코드를 보면서 공부하고 있는 대학생입니다.

      현재 이렇게 입력한 데이터값을 안드로이드 스튜디오에서 그래프화 시키고싶은데 어떻게 해야할지 하나도 감이 안잡힙니다..

      조언 부탁드립니다!!



      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.11.26 23:04 신고


        해보지는 않았지만 구글에서 검색해보니 몇가지 라이브러리가 있습니다.

        android graph library 로 찾아보세요.

      • W 2018.11.26 23:10


        혹시 그러면 데이터값이 앱 내에 변수로 저장이 되어있는건가요???

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.11.26 23:18 신고


        mArrayList에 저장됩니다.

      • 2018.11.27 03:46


        비밀댓글입니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.11.27 07:06 신고


        다음처럼 입력됩니다.


        PersonalData personalData = new PersonalData();

                       personalData.setMember_id(id);
                       personalData.setMember_name(name);
                       personalData.setMember_address(address);

                       mArrayList.add(personalData);
         

      • W 2018.11.27 09:31


        ArrayList<BarEntry> entries = new ArrayList<>();

        for (int i = 0; i<11; i++) {
        entries.add(mArrayList.get(i).getMember_time(), mArrayList.get(i).getMember_number());
        }

        이런식으로 작성하면 entries라는 배열에 mArrayList의 값이 저장되는것이 맞나요??

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.11.27 12:12 신고


        BarEntry 클래스를 어떻게 선언했나요?

      • w 2018.11.27 13:37


        BarChart barChart = (BarChart) findViewById(R.id.bargraph);

        ArrayList<String> entries = new ArrayList<String>();
        ArrayList<BarEntry> values = new ArrayList<BarEntry>();
        ArrayList<BarDataSet> dataSets = new ArrayList<BarDataSet>();
        BarDataSet set1;

        for (int i = 0; i<11; i++) {
        entries.add(mArrayList.get(i).getMember_time());
        values.add(mArrayList.get(i).getMember_number());
        }

        set1 = new BarDataSet(values, "Number");
        dataSets.add(set1);

        BarData data = new BarData(entries, values);

        data.setValueTextSize(10f);

        BarChart.setData(data);

        이렇게 했는데 현재

        BarData data = new BarData(entries, values); 에서 entries, values부분이 빨간줄뜨고,

        BarChart.setData(data); 부분에서 setData부분이 빨간줄이뜹니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.11.27 15:33 신고


        빨간줄이 보이는 부분에 마우스 커서를 가져가면 에러 원인이 보일듯합니다.

        또는 로그창에 보일듯합니다.

    • sam 2018.12.05 00:41


      안녕하세요. 자세한 설명과 답글들을 참고하여 DB로부터 데이터 불러오기까지 되었습니다.
      이 점에서 감사인사드립니다.
      알려주신 코드중에서
      GetData task = new GetData();
      task.execute( "http://" + IP_ADDRESS + "/getjson.php", "");
      이 부분을 일정시간간격으로 반복하여 실행함으로써
      최종적으로 저장된(가장 최신의) 데이터를 불러오고 싶어서 아래와 같이 타이머기능을 사용하여 코드를 작성하여 실행하면
      오류메시지와 함께 앱이 종료됩니다. 아직은 코드참고하는 수준이라 조언부탁드립니다.
      mTimer = new Timer();
      TimerTask m_task = new TimerTask() {
      @Override
      public void run() {
      task.execute( "http://" + IP_ADDRESS + "/getjson.php", "");
      }
      };
      mTimer.schedule(m_task,5000,1000);

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.12.05 08:15 신고


        다음처럼 핸들러를 사용하도록 해서 onCreate 메소드 마지막 줄에 넣으면 됩니다.

        final Handler handler = new Handler();
        Runnable runnableCode = new Runnable() {
        @Override
        public void run() {
        mArrayList.clear();
        mAdapter.notifyDataSetChanged();

        GetData task = new GetData();
        task.execute( "http://" + IP_ADDRESS + "/getjson.php", "");

        handler.postDelayed(this, 5000);
        }
        };
        handler.post(runnableCode);

      • sam 2018.12.05 11:11


        알려주신 코드를 사용하니 2주넘게 오류만 보이던 화면이 정상동작되었습니다. 바쁘신데도 사소한 질문에 해결책을 알려주셔서 정말 감사드립니다.
        앞으로도 열심히 배우겠습니다^^

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.12.05 11:11 신고


        다행이네요 ^^

    • 2019.04.09 18:44


      비밀댓글입니다

    • 2019.05.02 10:18


      비밀댓글입니다

    • pola 2019.05.02 13:00


      앞에 테이블생성할때 address가 아닌 country로 바꿔서 생성해야 작동하더라구요 혹시나 실행안되시는분들은 이 부분 주의해서 보시면될거같습니다.
      그리고 여쭤볼것이 있습니다만
      위의 테이블을 이용해서 다른테이블의 내용을 불러올수 있을까요?
      몇가지 재료를 입력하면 만들수있는 요리가 나오도록하는 어플을 만들어보고 있는데
      제가 소스를 어떻게 짜야하는지 잘모르겠습니다 pk,fk를 사용하는건알고있습니다만 구체적으로 어떻게해야하는지 피드백 받고싶습니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.02 13:24 신고


        미쳐 안바뀐 부분이 있었군요.. 알려주셔서 감사합니다.. 수정해두었습니다.

        물어보신 점은

        여러 테이블을 JOIN을 해서 여러 테이블의 레코드를 하나로 묶어서 가져오면 됩니다.

        sql join으로 검색하면 관련 내용을 찾으실 수 있습니다.

      • pola 2019.05.02 13:41


        피드백 감사드립니다 이 글이 정말 도움이 많이되었습니다 골머리를 앓고있던부분이였는데 시원하게 해결되었습니다 감사드립니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.02 13:55 신고


        감사합니다 : )

      • 2019.05.02 14:12


        비밀댓글입니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.02 15:02 신고


        머신러닝 또는 딥러닝으로 풀어야할 문제처럼 보이네요..

        요리별로 재료를 데이터베이스에 입력하고 sql 질의해서 중복된 재료가 많은 요리를 보여주면 어떨까 싶습니다.
        테이블 구조에 대한 고민이 필요할듯하군요..

      • pola 2019.05.02 15:20


        저도 같은 생각이고 앞으로 그부분을 중점적으로 해결하려고합니다. 그런데 중간에 코드에서 protected String doInBackground(String... params)부분이 두번이나 있는데 두번이나 쓰는 이유와 그 차이점이 무엇인지 알수있을까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.02 15:48 신고


        기존에 따로 작성되었던 두 개의 포스트에서 사용한 코드를 하나로 합치면서..
        중복된 부분을 하나로 합치지 않고 그냥 사용했기 때문입니다.

        중복된 부분을 합칠 수 있다면 하나로 해도 될듯합니다.

      • pola 2019.05.02 19:54


        친절한 답변 감사드립니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.03 00:07 신고


        감사합니다 : )

    • 안녕하세요 2019.05.21 16:39


      안녕하세요.. build.gradle에 implementation 'com.android.support:recyclerview-v7:28.0.0'를 넣고 useradapter에 import android.support.v7.widget.RecyclerView;를 넣으려고 했는데 v7 widget에 RecyclerView가 없네요ㅜㅜ 해결방법은 없을까요?

    • ggg 2019.05.24 12:13


      안녕하세요 데이터를 넣지않고 데이터베이스에 있는 정보만 검색해서 확인하려고 하는데 디버깅용에는 정보가 뜨는데 리스트뷰에는 아무것도 안떠요ㅠㅠ 오류같은것도 없는데 왜 이럴까요..

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.24 13:26 신고


        showResult에서 데이터가 확인되는지 보세요.

      • ggg 2019.05.24 13:44


        private void showResult(){

        String TAG_JSON="root";
        String TAG_ID = "id";
        String TAG_NAME = "name";
        String TAG_JUSO ="juso";

        try {
        JSONObject jsonObject = new JSONObject(mJsonString);
        JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);

        for (int i = 0; i < jsonArray.length(); i++) {

        JSONObject item = jsonArray.getJSONObject(i);

        String id = item.getString(TAG_ID);
        String name = item.getString(TAG_NAME);
        String address = item.getString(TAG_JUSO);

        PersonalData personalData = new PersonalData();

        personalData.setMember_id(id);
        personalData.setMember_name(name);
        personalData.setMember_address(address);

        mArrayList.add(personalData);
        mAdapter.notifyDataSetChanged();
        }
        }catch (JSONException e) {

        Log.d(TAG, "showResult : ", e);
        }

        }
        showResult코드가 이렇게 되는데 빠진거라도 있나요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.24 13:47 신고


        값이 넘어오는지 테스트해서 뭐가 문제인지 찾아야 할듯합니다. 코드만 봐서는 오류를 놓칠 확률이 높습니다.

    • 2019.05.28 14:38


      비밀댓글입니다

    • 우유비 2019.06.26 12:12


      안녕하세요. 포스팅에 큰 도움 받았습니다.

      문의드릴게 있습니다.
      dbcon.php 파일을 android app 단에 위치 시켜도 동작이 되나요??

    • midnight 2019.08.24 01:48


      로그캣에 E/RecyclerView: No layout manager attached; skipping layout 라고 뜹니다.
      Adapter에서 context에 접근이 안되서 문제가 발생하는 거라고 보고 있습니다.
      그런데 제가 초보다 보니 context를 어떻게 접근 해야 할지 모르겠습니다.
      이전에 올려주신 버튼 눌러서 데이터를 추가하던 글을 성공적으로 실행해 보고 이 코드로 수정을 해본건데 잘 뜨던 recyclerview가 왜 안뜨는지 모르겠습니다ㅠ 팁을 조금만 주시면 그쪽으로 더 공부해보겠습니다ㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.24 08:41 신고


        아래 코드가 추가되어 있나요?

        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

      • midnight 2019.08.24 10:19


        코드 정말 여러번 확인했는데 왜 못 봤을까요(당황) 감사합니다ㅎㅎ
        알려주신대로 해서 로그캣은 오류없이 처리가 되는데, recyclerview에 데이터가 안뜹니다.
        context문제가 아닌가요??ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.24 10:26 신고


        context는 안사용하는게 맞습니다.
        context 대신에 다음처럼 처리했었네요.
        viewGroup.getContext()

        포스트의 코드설명이라는 부분을 참고하여 따라가며 로그캣으로 문제없는지 출력해봐야 할듯합니다.

      • midnight 2019.08.27 18:06


        자꾸 질문드려서 죄송합니다ㅠ 계속 같은 문제에 막힙니다ㅠㅠ
        로그캣을 다시 봤는데 org.json.JSONException: Value  of type java.lang.String cannot be converted to JSONObject 라고 뜹니다.
        JSONObject jsonObject = new JSONObject(mJsonString); JSONArray jsonArray = jsonObject.getJSONArray(TAG_JSON);
        코드도 맞게 넣었는데 왜 그럴까요

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.27 18:24 신고


        mJsonString에 공백이 포함된건 아닌지 확인해보세요.

      • midnight 2019.08.27 20:40


        공백도 없는데, 혹시 다른 이유는 없을까요??

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.27 20:56 신고


        mJsonString에 저장되어 있는 문자열이 JSON 프로토콜에 맞지 않아서 발생한 에러로 보입니다.

        로그캣으로 출력된 mJsonString이 어떻게 보이나요?

      • 2019.08.29 14:04


        비밀댓글입니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.08.29 14:12 신고


        에러나는게 아래 내용 땜이 아닐까 싶습니다.

        다음 부분을 새로 정의하신 JSON에 맞추어 변경해야 합니다.

        String TAG_JSON="webnautes";
        String TAG_ID = "id";
        String TAG_NAME = "name";
        String TAG_COUNTRY ="country";


      • midnight 2019.09.16 15:13


        말씀해 주신대로 해도 해결이 잘 안나서 계속 여쭤보기도 죄송해서 혼자 해결 해보다 보니 감사 댓글이 늦었습니다!!^^
        JSONObject jsonObject = new JSONObject(mJsonString.substring(mJsonString.indexOf("{"),mJsonString.lastIndexOf("}") +1));
        이렇게 한줄을 바꾸니까 해결이 되었습니다!
        선생님 블로그 보면서 진짜 많이 배웠습니다^^ 에러 관련해서 도움도 많이 주셔서 정말정말 너무 감사합니다^^

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.16 15:15 신고


        해결해서 다행입니다^^ 감사합니다

    • 차도미 2019.09.03 14:12


      나라를 검색하는 부분에서 전체보기는 문제 없이 읽히는데,
      검색버튼을 누르면 아무것도 뜨지 않습니다.
      디버깅용 문자에는 검색할 나라를 입력하라고만 뜨는데, 어떠한 값을 입력해도
      위와 같은 문자만 출력이됩니다.

      혹시나해서 주소로 쳐서 들어가서 확인할때는 정상동작하는데,
      앱으로 실행했을 경우 위와같은 문제가 생기네요..

      EditText 부분을 못 읽는것 같은데 혹시 원인을 알 수 있을까요!?ㅎㅎ

      감사합니다...

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.03 14:27 신고


        다음 코드에서 Keyword가 출력되나 로그캣으로 확인해보세요.

        String Keyword = mEditTextSearchKeyword.getText().toString();
        mEditTextSearchKeyword.setText("");

        GetData task = new GetData();
        task.execute( "http://" + IP_ADDRESS + "/query.php", Keyword);

      • 차도미 2019.09.03 15:24


        mTextViewResult.setText(Keyword);
        Log.d(TAG, " Keyword - " + Keyword);

        밑에 추가해서 확인해봤는데, 로그켓에서는 값을 확인할 수 있었습니다...
        다른 문제가 있을까요..?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.03 15:29 신고


        task.excute 아규먼트로 주어지는 URL을 로그캣으로 출력해서 웹브라우저에서 접속하는데 문제 없나 확인해보세요

      • 차도미 2019.09.03 15:57


        아 죄송합니다..
        doInBackground 이 부분에서
        String serverURL = params[0];
        String postParameters = "Country=" + params[1];

        이 부분이 잘못 되어있었네요..
        오타라니...
        귀한 시간 답변 해주셔서 감사합니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.03 15:59 신고


        원인을 찾아서 다행입니다 : )

    • 빨간머리차차 2019.12.14 17:22


      그 혹시 이미지도 저장 및 업로드 하는 방법을 해주실 생각은 없나요?

Designed by Tistory.