반응형




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

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



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

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



최초 작성 - 2018.   6. 17

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

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





1. 동작 설명

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

3. 관련 포스팅

4. 참고



 

Amazon AWS를 사용하여 구현한 예제입니다.

 

AWS Rest API를 Android와 연동해보기( Lambda + API Gateway + DynamoDB )

https://webnautes.tistory.com/1590

 

 

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




반응형

해보고 확인한 것을 문서화하여 기록합니다.
최소 일주일에 한번 이상 포스트를 하려고 노력중입니다.

부족함이 있지만 도움이 되었으면 합니다.
잘못된 부분이나 개선점을 알려주시면 감사하겠습니다.



포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
시간날때 마다 이전 포스트가 문제 있는지 확인을 해보려고 노력하고 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.


제가 쓴 책도 한번 검토해보세요 ^^

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기

댓글을 달아 주세요

">
  1. 이전 댓글 더보기
  2. thumbnail
    pola
    2019.05.02 13:00

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

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

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

      물어보신 점은

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

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

    • thumbnail
      pola
      2019.05.02 13:41

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

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

      감사합니다 : )

    • thumbnail
      익명
      2019.05.02 14:12

      비밀댓글입니다

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

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

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

    • thumbnail
      pola
      2019.05.02 15:20

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

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

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

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

    • thumbnail
      pola
      2019.05.02 19:54

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

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

      감사합니다 : )

  3. thumbnail
    안녕하세요
    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가 없네요ㅜㅜ 해결방법은 없을까요?

  4. thumbnail
    ggg
    2019.05.24 12:13

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

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

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

    • thumbnail
      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코드가 이렇게 되는데 빠진거라도 있나요?

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

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

  5. thumbnail
    익명
    2019.05.28 14:38

    비밀댓글입니다

  6. thumbnail
    우유비
    2019.06.26 12:12

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

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

  7. thumbnail
    midnight
    2019.08.24 01:48

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

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

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

      mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    • thumbnail
      midnight
      2019.08.24 10:19

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

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

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

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

    • thumbnail
      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);
      코드도 맞게 넣었는데 왜 그럴까요

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

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

    • thumbnail
      midnight
      2019.08.27 20:40

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

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

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

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

    • thumbnail
      익명
      2019.08.29 14:04

      비밀댓글입니다

    • thumbnail
      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";


    • thumbnail
      midnight
      2019.09.16 15:13

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

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

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

  8. thumbnail
    차도미
    2019.09.03 14:12

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

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

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

    감사합니다...

    • thumbnail
      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);

    • thumbnail
      차도미
      2019.09.03 15:24

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

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

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

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

    • thumbnail
      차도미
      2019.09.03 15:57

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

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

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

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

  9. thumbnail
    빨간머리차차
    2019.12.14 17:22

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

  10. thumbnail
    ㅎㄹ
    2020.04.20 12:31

    안녕하세요. 혹시 검색할 때 일정 단어를 포함한 단어들 모두 불러오는 방법은 없을까요?
    선생님 예제 같은 경우에 '이탈' 만 검색해도 이탈리아가 뜨는 경우로요,,!

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.20 12:34 신고

      sql에서 일부 문자열로 검색하는 방법을 찾아보시면 될거 같습니다. sql문만 수정하면 됩니다.

    • thumbnail
      ㅎㄹ
      2020.04.20 12:52

      선생님 예제 같은 경우에는
      SELECT name, country FROM person WHERE country LIKE '%이탈%'
      이렇게 수정하는 거 맞나요?

      이렇게 하면 테이블에서만 수정이 되고 안드로이드에서는 안되는거 같은데 단말기에서 특정 포함 검색 후 단어 불러오는 법은 없나요?
      아니면 제가 선생님의 말씀을 잘못 짚고 있는 걸까요ㅠㅠ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.04.20 19:54 신고

      맞게 접근하신거 같습니다. mysql에선 질의 결과가 있는데 안드로이드와ㅜ연동하면 결과가 없나요?

  11. thumbnail
    opppp
    2020.05.07 16:59

    전체보기를 눌렀을때 아무것도 안나와요 ..

  12. thumbnail
    아이템클릭시
    2020.05.15 19:27

    안녕하세요
    리사이클러뷰 아이템 클릭시 그 데이터값을 액티비티로 넘기는 방법좀알려주세요 ㅜ. 눌렀을때 액티비티로 넘어가는거까진했는데 데이터값을 어떻게 가지고오는지 모르겠어요
    예를들어 첫번째항목 제목 -- 내용 -- 작성자가 있을때 이걸 클릭하면 상세페이지로 넘어가면서 제목 내용 작성자 그대로 불러오고싶어요

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.05.16 02:49 신고

      리싸이클러뷰의 아이템 길게 누르면 해당 아이템 가져오는 건 아래 포스트를 참고하세요.

      https://webnautes.tistory.com/1222


      액티비티간 데이터 넘겨주는건 아래 포스트를 참고하세요

      https://webnautes.tistory.com/1012

  13. thumbnail
    초보계발
    2020.05.26 11:52

    Deprecated: Function get_magic_quotes_gpc() is deprecated in C:\xampp\htdocs\dbcon.php on line 23

    이게 매번뜨는데 혹시 없애는 방법 있나요

    그리고 혹시 저 메세지도 앱으로 같이 들어오고
    Function get_magic_quotes_gpc() is deprecated in <b>C:\xampp\htdocs\dbconf.php</b> on line <b>23</b><br />{ "root": [ { "id": "5", "name": "Roony", "country": "USA" } ]}
    이런식으로 출력 됩니다..
    이것때문에 리사이클러뷰에 출력이 안되는것일까요?

    org.json.JSONException: Value <br of type java.lang.String cannot be converted to JSONObject
    이 에러가 발생하네요ㅎ 그래서 catch로 빠진게 아닐까 싶습니다.ㅠㅠ

    • thumbnail
      초보계발
      2020.05.26 13:58

      PHP를 몰라서 ㅎㅎ..
      get_magic_quotes_gpc()
      이 함수가 이제 사용 안하는 함수인가봐요
      그래서 처음에
      if(function_exists('get_magic_quotes_gpc') && true) 로 했다가 사용안하는 함수인거 같아서 if문을 없애버렸습니다.
      그랬더니 이제 웹(?)에서도
      Deprecated: Function get_magic_quotes_gpc() is deprecated in C:\xampp\htdocs\dbcon.php on line 23
      문구가 없어졌습니다.
      물론 동작도 잘되구요(앱, php -> DB)
      ㅎㅎ PHP를 몰라서 함수를 제거해도 문제가 없는지는 모르겠지만 작동합니다.
      좋은예제 감사합니다.ㅎㅎ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2020.05.26 20:05 신고

      PHP 최신 버전에서 get_magic_quotes_gpc() 함수가 deprecated되었나 봅니다. 언젠가 나오는 버전에서는 이 함수가 제거될거라는 의미입니다.

      해결되었다니 다행이네요.. 감사합니다.

  14. thumbnail
    Neoc
    2020.07.01 11:27

    안녕하세요.
    포스팅 보고 안드로이드와 php연결해서 FAQ를 하나 만들어봤는데요.
    상단에 회원/구매/기타 이런식으로 메뉴를 두고 클릭시
    mArrayList.clear();
    mAdapter.notifyDataSetChanged();

    GetData task = new GetData();
    task.execute( "http://" + IP_ADDRESS + "/getjson.php", "");
    포스팅처럼 구현했습니다.
    단 FAQ라서 질문만 보이고 답변은 클릭시 Adapter에서 setVisibility를 변경해서 보이게 해줬는데요.
    회원부분에서 첫번째를 클릭해서 답변을 보이게 변경하고, 구매탭을 눌러서 위의 4줄로 구매탭 내용이 보이는데
    구매탭의 첫번째 질문에 답변이 보인상태로 표시됩니다.
    여기저기 다 검색해봐도 마땅한 해결책을 못찾아서 어떻게 해야되는지 해결방법에 대한 자문을 좀 구할수 있을까요?
    https://dev-imaec.tistory.com/30 제목 클릭시 답변이 보이게 하는건 저 블로그를 참고해서 구현하였습니다.

  15. thumbnail
    Favicon of https://rrojin.tistory.com BlogIcon rrojin

    좋은 글 감사합니다! 디비 전체 조회 결과를 다른 화면에 띄울려면 어떻게 해야하나요?
    버튼 onClick()에 아래와 같이 적은 후에,,
    Intent intent = new Intent(getApplicationContext(), MySqlActivity.class);
    startActivity(intent);

  16. thumbnail
    hhhhhh
    2020.10.21 23:20

    안녕하세요 덕분에 너무 도움이 많이 되었습니다. 친절하게 알려주신 덕분에 sql저장, 검색, 출력은 잘 이해하였는데 제가 지식이 부족해서 응용하는 법이 부족한것 같습니다. 혹시 수정이나 삭제는 어떤 방식으로 해야할지 알수 있을까요 바쁘실텐데 부탁드려요ㅠㅠ

  17. thumbnail
    Favicon of https://kjhong94.tistory.com BlogIcon 홍규종

    디폴트 디비를 MySQL로 잘했는대도
    Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'webnautes'@'localhost' (using password: YES)
    이오류가 뜨면 어떻게 해야 하아요?

  18. thumbnail
    Favicon of https://mylife3904.tistory.com BlogIcon 코딩바보최수환

    좋은 글 감사합니다. 많이 배우고 있습니다!
    다름 아니라, 위의 insert.php 파일을 활용해서 update.php를 만들어 데이터를 수정하고 싶어 많이 수정해봤지만 하지 못했습니다. 혹시 이에 대해 팁을 주실 수 있으실까요?
    부족한 제 실력으로는, 안드로이드 코드는 InsertData 클래스에서 크게 건드릴 게 없이 갖다 쓰고, php를 어느 정도 만지면 되지 않을까 생각하고 있습니다.
    제가 현재 막힌 부분은 UPDATE 구문을 구성하는 데에 있어 어려움을 겪고 있습니다. 다른 곳과는 조금 다르게 사용되고 있는 것 같다고 생각했는데, 도움을 주실 수 있을까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.05.22 05:30 신고

      안드로이드 코드의 다음부분과 관련 php코드를 수정하면 됩니다.

      String postParameters = "name=" + name + "&country=" + country;

    • thumbnail
      Favicon of https://mylife3904.tistory.com BlogIcon 코딩바보최수환
      2021.05.22 16:43 신고

      생각보다 빠르게 답해주셔서 너무나 감사드립니다! 말씀해주신 코드 관련 php 코드라 하면 구체적으로 어떤 걸 말씀하시는지 알 수 있을까요?
      제가 추측하기로는, insert.php의 try 부분을 수정하라는 의미로 받아들였는데, SQL 구문도 계속 수정하고 이것저것 해봤는데 실패했습니다.
      제 생각이 틀렸다면 어떤 의미인지, 맞다면 구체적으로 어떻게 수정해야 할지 알려주실 수 있을까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.05.22 16:47 신고

      php 코드보면 name과 country를 지정하는 부분이 있고 안드로이드에도 name과 country를 지정하는 부분이 있습니다. 기존 포스트의 코드를 보고 연구해보세요

    • thumbnail
      Favicon of https://mylife3904.tistory.com BlogIcon 코딩바보최수환
      2021.05.22 16:57 신고

      아! 방금 SQL 구문 수정하여 php파일 실행에는 성공하였습니다!
      이제 php에서 해당 항목의 id값을 가져와서 UPDATE를 하고 싶은데, 혹시 이에 대한 방법을 알 수 있을까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.05.22 17:00 신고

      해보지 않았는데 포스트에서 했던 insert와 같은 방식으로 가능할듯합니다. 안드로이드에서 php로 데이터만 넘겨주면 되니깐요

    • thumbnail
      Favicon of https://mylife3904.tistory.com BlogIcon 코딩바보최수환
      2021.05.22 17:06 신고

      아 그렇군요! 그러면 지금 안드로이드에서 id값을 추가로 넘겨주는 방식이 가장 먼저 떠올랐는데, 그렇다면 안드로이드에서 해당 항목의 id값을 알아야 할텐데... 열심히 고민하고 있습니다만은 혹시 어떻게 하면 좋을지 알고 계실까요?

  19. thumbnail
    익명
    2021.05.24 08:29

    비밀댓글입니다

  20. thumbnail
    Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가

    선생님 질문이 있습니다.JSONObject jsonObject = new JSONObject(mjsonString) 이 부분에서 String을 json으로 변환이 안된다는 오류가 있어서 mjsonString의 문제인 것 같아 showresult를 호출하기 전 mjsonString=result 부분에 토스트메시지로 mjsonstring이 어떻게 뜨는지 확인해보았습니다. 그런데 메시지를 보니 <Html><Head><Title>400 Bad Request</Title></Head><Body><H1>400 Bad Request</H1>Your client has issued a malformed or illegal request.</Body></Html> 이 뜨더라고요 400 오류는 잘못된 요청이라는 것 같은데 원래 mJsonString에는 어떤 정보가 저장되는 걸까요..? 요청이 잘못됐다면 onpostexecute를 호출하는 친구에서 오류가 나는건가요??

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 14:24 신고

      웹브라우저에서 동작하나 보세요.

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 14:25 신고

      php 별로 테스트해볼수 있습니다

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 14:29 신고

      제 php 파일 이름이 marker.php인데 크롬상에서 localhost/marker.php하면 getjson예제에서 나라랑 그런거 뜨는것 처럼 "heartbeat": [
      {
      "Building": "태봉리보건진료소 (태봉리보건진료소)",
      "Latitude": "37.30272704",
      "Longitude": "127.1267642"
      },
      이런 식으로 나옵니다.. 그럼 웹에서는 동작 되는거 아닐까요..?

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 14:43 신고

      선생님 AsyncTask 게시글을 보니 doinbackgroud가 끝나면 return 된 값을onpostexcute가 파라미터로 받아서 호출이 되고 리턴한 값이 sb.toString().trim()인데 뒤에는 string으로 바꾸고 공백 제거한거니까 sb를 봐야하는데 StringBuilder는 문자열 저장 및 변경 클래스라고 하더라고요
      반복문에 bufferdReader.readline이 null이 아니면 sb에 line을 추가하던데 line에서 추가된 게 형식에 맞지 않았던걸까요

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 15:35 신고

      웹에서 결과값은 제대로 나오는게 맞습니다.에러를 다시보니 요청하는 부분이 잘못된거 같습니다.

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 15:37 신고

      안드로이드에서 서버에 요청하여 php에 접근할때 문법적 또는 URL 오류가 있어보입니다

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 15:55 신고

      URL부분은 안드로이드 돌리는 pc랑 아파치 서버 pc랑 같은거면 10.0.2.2로 하라고 하셨는데 제가 맵뷰를 띄워야해서 개인 디바이스로 테스트를 하다 보니 socketTimeoutException이 나오더라고요 그래서 인터넷 보니 무슨 ip를 써야 한다고 해서 네이버에 내ip검색하면 나오는 그 ip를 입력했더니 소켓타임아웃 예외는 안뜨더라고요 getdata 객체 만들어서 task.execute 하고 "http://"+IP_ADDRESS+"/marker.php", "" 이런식으로 쓰는데 Url 부분은 맞는거겠죠?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 16:04 신고

      에뮬레이터가 아니라면 안드로이드폰과 PC가 같은 아이피대역을 사용해야 합니다. 예를들어 같은 공유기에서 할당받은 IP

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 16:04 신고

      responseStatusCode가 Http_ok면 200이어야 할텐데 로그를 보니 400이 뜹니다.. 그래서 inputstream에 에러가 들어가고 그래서 json형식에 안맞나 봅니다..

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 16:05 신고

      변경한게 있나요

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 16:20 신고

      progressDialog.dismiss();
      if(result == null) {
      Toast.makeText(mContext, errorString, Toast.LENGTH_SHORT).show();

      제가 텍스트뷰 쓰는게 없어서 result가 비어잇으면 에러 메시지를 토스트로 띄우려고 햇습니다.
      이거말고 getdata에서 다른건 없는데 여기 포스팅은 postparameters가 "country=" + params[1]이던데 제가 처음 봤던 게시글은 그냥 params[1]이었거든요 그냥 params[1]로 하긴 했습니다.. 그런데 아이피는 iptime 관리자에서 외부 ip 주소로 나오는걸 쓰면 될까요 아님 ipconfig에서 기본 게이트웨이 192.168.으로 시작하는걸 쓰는걸까요.. 외부 ip가 맞겠죠ㅕ??

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 16:23 신고

      핸폰과 피시 모두 공유기를 써야합니다. 192.168 아이피를 사용해야 합니다

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 16:33 신고

      ip문제였던것 같습니다... 살짝 허무하긴 하네요 잘 알아봤어야 했는데.. 그런데 문제는 dbcon.php에서 성공 메세지때문에 php를 긁어서 바꿔보았는데 get_magic_quotes_gpc()가 deprecated돼서 저 메시지가 나오는바람에 저게 또 json 형식에 안맞다고 쿠사리를 넣네요... 저거만 또 찾아보면 될것같습니다. reponseStatuscode는 200 정상적으로 나오네요 너무 감사합니다. ㅠㅠ

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.06.04 16:43 신고

      다행입니다. 해당 함수는 사용안해도 되는 것으로 알고있습니다

    • thumbnail
      Favicon of https://ehlswkd11.tistory.com BlogIcon 즈가
      2021.06.04 16:46 신고

      아 그냥 지워도 되는건가요.. 너무 감사해요 ㅠㅠㅠ

  21. thumbnail
    Favicon of https://kko-ng.tistory.com BlogIcon kko_ng

    좋은 글 감사합니다. 도움 많이 받았습니다.
    질문이 있어 댓글 남깁니다.
    게시글 잘 따라가서 제 DB에 맞게 구현하는것 까지 성공했는데, 지금 진행중인 다른 앱에 적용을 시키려고 코드를 옮겼는데
    "java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference" 가 뜨네요..
    프레그먼트에 리사이클러뷰를 넣어서 구현했는데 이 때문인지, 아니면 제 앱에서는 검색 버튼을 없애고 프레그먼트가 로드 될때 바로 띄울 수 있게 keyword에 어떤 값을 집어넣어 놓은 채로 돌리는 중입니다. 도저히 모르겠네요.. 혹시 짐작가는 부분 없을까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.08.18 17:23 신고

      텍스트뷰 객체가 할당되기전에 사용하려고 시도해서 에러 났다는 거 같습니다. 값을 넣기전에 널 객체인지 체크해보면 어떨까 싶네요

    • thumbnail
      Favicon of https://kko-ng.tistory.com BlogIcon kko_ng
      2021.08.18 17:35 신고

      빠른 답변 감사합니다 main.java 코드 에서 onPostExecute함수에서 mTextViewResult.setText(result); <-이 줄에서
      저런 오류가 나는데 어떻게 체크하면 될까요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.08.18 17:42 신고

      네 그러면 될거 같습니다. 근본적으로는 호출하신 시점에서 왜 텍스트뷰객체가 널 객체인지 찾아야 할듯합니다.

    • thumbnail
      Favicon of https://kko-ng.tistory.com BlogIcon kko_ng
      2021.08.18 18:05 신고

      result에 null이 받아와지는 문제가 있어서 php코드를 수정하여 해결했습니다.

      하지만 result에 정보가 잘 들어와도 여전히 동일한 오류가 뜹니다. 디버깅 기능을 통해 result에 json과 유사한 배열이 들어오는것을 확인했습니다. 하..근데 왜.. result에 정상적으로 값이 들어와도
      java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference 오류가 발생할 수 있나요?

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.08.18 18:18 신고

      UI 문제입니다. 텍스트뷰 객체를 사용하는 시점에 널 객체라는 의미입니다

    • thumbnail
      Favicon of https://kko-ng.tistory.com BlogIcon kko_ng
      2021.08.18 20:17 신고

      후아....선생님 말씀대로 왜 null나오는지부터 거꾸로 쭉 들어가서 결국 해결했습니다.

      게시물부터 질문까지 많은 도움 받고갑니다. 감사합니다. ( _ _ )

    • thumbnail
      Favicon of https://webnautes.tistory.com BlogIcon webnautes
      2021.08.18 20:18 신고

      해결되서 다행입니다