안드로이드 앱이  PHP 프로그램을 매개로 하여 MySQL 데이터베이스 서버에 데이터를 저장하는 간단한 예제입니다. 



1. Apache2, MySQL, PHP7 설치

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

3. 웹브라우저로 PHP 동작  테스트

4. Android 앱에서 테스트

5. 코드 설명

6. 관련 포스팅

7. 참고


2015. 11. 21 최초 작성 

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

2020.  7. 14  MySQL을 디폴트로 바꾸는 방법 추가 



안드로이드 앱에서 바로 MySQL에 접속한다면 구현이 간단할 수 있습니다.

하지만 리버스 엔지니어링을 통해 안드로이드 앱에서 소스코드를 추출하게 되면 서버 아이피와 MySQL 서버 접속용 아이디와 패스워드가 유출될 수 있습니다. 


그래서 웹서버에서 실행되는 PHP를 이용하여 진행하게 됩니다.  안드로이드 앱의 코드를 추출한다 해도 서버 IP와 실행되는 PHP 파일 이름만 알 수 있습니다. 

하지만 해당 IP와 PHP 파일에 대한 정보를 통해 악용할 수도 있기 때문에 추가로 필요한 작업이 있을 수도 있을 듯하지만 제가 아는 범위에서 벗어나서 논외로 합니다. 

 



1. Apache2, MySQL, PHP7 설치

서버로 사용하려는 운영체제에 따라 1-1 또는 1-2를 진행하세요.

1-1. WIndows

다음 포스팅을 참고하여 윈도우에 WAMP( Apache2, MySQL , PHP7)를 설치합니다. 



윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

http://webnautes.tistory.com/1206 




오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 PHP > Version을 선택합니다. 


사용가능한 PHP 버전이 보이는 데 최신 버전인 7.2.18를 선택합니다. 글 작성시점과 버전이 다를 수 있습니다. 





1-2. Ubuntu

다음 포스팅을 참고하여 Ubuntu에  LAMP( Apache2, MySQL , PHP7)를 설치합니다. 



Ubuntu 18.04에 LAMP ( Apache2, MySQL , PHP7) 설치하는 방법

http://webnautes.tistory.com/1185    





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


2-1. MySQL에서 데이터베이스를 새로 생성하고  해당 데이베이스를 접근할 수 있는 사용자를 추가하는 방법을 설명합니다. 


서버 컴퓨터의 운영체제가 Windows라면 2-2, Ubuntu라면 2-3을 진행하세요.




2-2. 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다. 


로그인 사용자로 root가 지정되어 있습니다. OK 버튼을 클릭합니다. 




Enter password: 라는 메시지가 보입니다.  설치시 설정해주었던 root 암호를 입력해주면 로그인이 완료됩니다. 


root 암호를 설정한 적이 없다면 엔터를 입력하여 진행할 수도 있지만 포스팅의 1-1을 다시 진행하여 root 암호를 부여해주세요.. 



이제 2-4를 진행하세요.




2-3. Ubuntu 18.04에서 설치한 MySQL에서는 디폴트로 auth_socket 플러그인을 사용하기 때문에 기존에 사용하던 방법(root 계정의 암호입력)으로 로그인이 되지 않습니다. 


확인을 못해봤는데 Ubuntu 16.04에서 최신 버전 MySQL을 사용한다면 같은 상황이 있을 수 있습니다. 


webnautes@webnautes-pc:~$ mysql -u root -p
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'



sudo 명령시 입력하는 사용자 암호 입력으로 기존 로그인을 대체합니다.


webnautes@webnautes-pc:~$ sudo mysql
[sudo] webnautes의 암호:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 5.7.22-0ubuntu18.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql>




2-4. 윈도우와 우분투에서 동일하게 진행하는 부분입니다.


데이터베이스를 생성합니다. 


mysql> create database 데이터베이스이름 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


mysql> create database testdb default character set utf8;

Query OK, 1 row affected (0.00 sec)



새로 생성한 데이터베이스를 사용할 사용자를 생성합니다. 


mysql> create user 사용자이름 identified by '패스워드';


mysql> create user webnautes identified by 'apple9!';

Query OK, 0 rows affected (0.01 sec)



앞에서 생성했던 데이터베이스를 새로 생성한 사용자가 사용하도록 권한을 부여합니다.  


mysql> GRANT ALL PRIVILEGES ON 데이터베이스이름.* TO '사용자이름'@'localhost' identified by '패스워드';


mysql> grant all privileges on testdb.* to 'webnautes'@'localhost' identified by 'apple9!';

Query OK, 0 rows affected, 1 warning (0.00 sec)



quit를 입력하여 MySQL 콘솔을 종료합니다.




2-5.  MySQL 콘솔에 새로 생성한 사용자로 접속합니다. 


우분투에서는 다음처럼 MySQL 로그인을 합니다. 사용자 이름은 새로 생성한 데이터베이스 접근권한을 가진 사용자 입니다. 

Enter password: 에 사용자의 암호를 입력해줍니다. 


$ mysql -u 사용자이름 -p

Enter password:



윈도우에서는 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다.


새로 생성한 데이터베이스 접근권한을 가진 사용자 이름을 적고 OK 버튼을 클릭합니다. 




Enter password: 메시지가 보이면 사용자의 암호를 입력해줍니다. 


Enter password:




2-6. 데이터베이스 testdb에 필요한 테이블 person을 생성하고  MySQL이 잘 동작하는지 여부를 다음처럼 확인합니다. 


앞에서 생성해두었던 데이터베이스 testdb가 보입니다.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| testdb             |
+--------------------+
2 rows in set (0.00 sec)


데이터베이스 testdb를 사용하도록 하고

mysql> use testdb;
Database changed



다음 명령을 복사 후 붙여넣기 해서 person 테이블을 생성합니다.

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;


mysql> 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;
Query OK, 0 rows affected (0.03 sec)


person 테이블이 생성되었습니다.


mysql> show tables;
+--------------+
| Tables_in_db |
+--------------+
| person       |
+--------------+
1 row in set (0.00 sec)


데이터 하나를 테이블에 입력 해봅니다. 


mysql> insert into person(name, country) values('test', 'test');
Query OK, 1 row affected (0.00 sec)


쿼리를 해서 데이터를 다시 가져와 봅니다.

 
mysql> select * from person;
+----+------+---------+
| id | name | country |
+----+------+---------+
|  1 | test | test    |
+----+------+---------+
1 row in set (0.00 sec)


person 테이블의 데이터를 초기화합니다. 


mysql> truncate person;
Query OK, 0 rows affected (0.01 sec)


테이블이 초기화 되었습니다.


mysql> select * from person;

Empty set (0.00 sec)


MySQL 콘솔을 종료합니다.


mysql> exit
Bye




3. 웹브라우저로 PHP 동작  테스트

Android 앱으로 테스트를  진행하기 전에 다음 PHP 코드를  웹 브라우저로 간단한 테스트를 해보겠습니다.


다음 두 개의 파일이 필요합니다.

dbcon.php

MySQL 서버 접속을 위해 사용되는 코드입니다. 


insert.php

지정해 높은 데이터베이스의 테이블에 데이터를 저장하기 위해 사용됩니다.



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


<?php

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

    include('dbcon.php');


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

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

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

        if(!isset($errMSG))
        {
            try{
                $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());
            }
        }

    }
?>

<html>
  <body>
        <?php
        if (isset($errMSG)) echo $errMSG;
        if (isset($successMSG)) echo $successMSG;
        ?>
       
        <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>




3-1. 윈도우라면 C:\wamp64\www\ 경로에 파일을 생성합니다.



3-2. 우분투라면 /var/www/html/ 경로에 파일을 생성합니다.



3-3. 웹브라우저에서  localhost/insert.php 주소로 접속하면 아래와 같은 화면이 보이게 됩니다. 





최근에 나온(2020. 7. 14 기준)  WampServer의 경우 프로그램 설치시 MySQL를 선택해야 설치되며  디폴트 데이터베이스가 아래 스크린샷처럼 MariaDB로 되어 있습니다. 

WampServer 트레이 아이콘에서 왼쪽 버튼으로 클릭하면 보입니다. 


MySQL을 디폴트로 변경하지 않으면 다음과 같은 에러가 날 수 있습니다. 

얼마전 이 에러를 질문하신분이 있었는데 이런 문제가 있는줄 몰랐네요..


Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'webnautes'@'localhost' (using password: YES) 





WampServer 트레이아이콘에서 마우스 오른쪽 버튼을 눌러  보이는 메뉴에서 Tools > Invert default DBMS MariaDB <-> MySQL을 선택합니다. 

디폴트 DBMS가 MariaDB에서 MySQL으로 변경되게 됩니다. 



다음처럼 MySQL이 디폴트로 바뀌어야 합니다. 





정상적으로 테이블에 데이터가 입력되면 출력되는 메시지입니다.




이름이나 나라를 입력하지 않으면 에러 메시지를 출력하도록 되어 있습니다.






3-4. 안드로이드 폰의 웹브라우저에서도 테스트해 봅니다.




접속에 문제가 있다면 다음 포스트 16번부터  참고하세요.



윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

 http://webnautes.tistory.com/1206 





3-5. MySQL에서 확인해보면 데이터가 정상적으로 입력된 것을 볼 수 있습니다. 


SELECT 문으로 testdb 데이터베이스에 있는 Person 테이블의 내용을 조회합니다.

웹에서 입력한 이름과 주소가 제대로 입력되었는지 확인가능합니다.





4. Android 앱에서 테스트


웹서버의 PHP 파일을 통해 데이터베이스에 데이터를 저장하는 안드로이드 앱을 작성합니다.



4-1. insert.php 파일을 다음 코드로 변경합니다. 


<?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
    }
?>




4-2. AndroidManifest.xml 매니페스트 파일의  manifest 태그 하위 항목으로 인터넷 접근 허용 퍼미션을 추가합니다.

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"


 


4-3. activity_main.xml 레이아웃 파일을 아래 내용으로 바꿉니다. 



<?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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name"
        android:id="@+id/textView_main_name" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText_main_name" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Country"
        android:id="@+id/textView_main_country" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editText_main_country" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Insert"
        android:id="@+id/button_main_insert" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:id="@+id/textView_main_result" />

</LinearLayout>




4-4. MainActivity.java 자바 파일을 아래 내용으로 바꿉니다.



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

private static String IP_ADDRESS = "IP주소";


안드로이드 에뮬레이터와 서버가 같은 컴퓨터에 동작하는 경우에는 다음 아이피를 입력합니다.

Android Studio의 에뮬레이터  - 10.0.2.2

GenyMotion - 192.168.56.1  


package com.tistory.webnautes.phptest;

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
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 java.io.BufferedReader;

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

import java.net.HttpURLConnection;
import java.net.URL;


public class MainActivity extends AppCompatActivity {

    private static String IP_ADDRESS = "IP주소";
    private static String TAG = "phptest";

    private EditText mEditTextName;
    private EditText mEditTextCountry;
    private TextView mTextViewResult;


    @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);

        mTextViewResult.setMovementMethod(new ScrollingMovementMethod());


        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("");

            }
        });

    }



    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());
            }

        }
    }


}




4-5.  안드로이드 프로젝트를 빌드하여 앱을 테스트할 디바이스 또는 에뮬레이터에 설치합니다.

앱을 실행시키면 다음과 같은 화면이 보입니다.




테스트 문자열을 입력하고  INSERT를 터치합니다. 




성공한 경우 SQL문 처리 성공이라는 메시지가 보이게 됩니다.




Error: connect timed out 메시지가 보인다면 본 포스트의 3-4를 다시 확인해보세요.

방어벽 문제 일 수 있습니다. 




4-6. MySQL에서 확인해보면 정상적으로 입력된 것을 볼 수 있습니다.





5. 코드 설명

다음 두 단계를 거쳐서 안드로이드 앱의 데이터가 MySQL 서버에 저장됩니다. 


  1. 안드로이드 앱에서 POST 방식으로 PHP 코드에 데이터를 전달합니다. 

  2. PHP 코드에서 MySQL 서버에 접속하여 전달받은 데이터를 저장합니다.



우선 안드로이드 앱 코드를 살펴보겠습니다. 


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

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


      // 1. PHP 파일을 실행시킬 수 있는 주소와 전송할 데이터를 준비합니다.

      // POST 방식으로 데이터 전달시에는 데이터가 주소에 직접 입력되지 않습니다.
String serverURL = (String)params[0];



      // HTTP 메시지 본문에 포함되어 전송되기 때문에 따로 데이터를 준비해야 합니다. 

      // 전송할 데이터는 “이름=값” 형식이며 여러 개를 보내야 할 경우에는 항목 사이에 &를 추가합니다.     

      // 여기에 적어준 이름을 나중에 PHP에서 사용하여 값을 얻게 됩니다.

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


try {
            // 2. HttpURLConnection 클래스를 사용하여 POST 방식으로 데이터를 전송합니다.
URL url = new URL(serverURL); // 주소가 저장된 변수를 이곳에 입력합니다. 


            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

httpURLConnection.setReadTimeout(5000); //5초안에 응답이 오지 않으면 예외가 발생합니다.

httpURLConnection.setConnectTimeout(5000); //5초안에 연결이 안되면 예외가 발생합니다.

httpURLConnection.setRequestMethod("POST"); //요청 방식을 POST로 합니다.
httpURLConnection.connect();


OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(postParameters.getBytes("UTF-8")); //전송할 데이터가 저장된 변수를 이곳에 입력합니다. 인코딩을 고려해줘야 합니다.

outputStream.flush();
outputStream.close();


            // 3. 응답을 읽습니다.   

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();
}


            // 4. StringBuilder를 사용하여 수신되는 데이터를 저장합니다.
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();

            

            // 5. 저장된 데이터를 스트링으로 변환하여 리턴합니다.
return sb.toString();


} catch (Exception e) {

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

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

}




PHP 코드를 보겠습니다. 

 

        // 1. 안드로이드 코드의 postParameters 변수에 적어준 이름을 가지고 값을 전달 받습니다.
        $name=$_POST['name'];
        $country=$_POST['country'];


    
        // 2. 입력안된 항목이 있을 경우 에러 메시지를 생성합니다.
        if(empty($name)){
            $errMSG = "이름을 입력하세요.";
        }
        else if(empty($country)){
            $errMSG = "나라를 입력하세요.";
        }

        // 3. 에러 메시지가 정의안되어 있다면 이름과 나라 모두 입력된 경우입니다. 

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

                // 5. SQL 실행 결과를 위한 메시지를 생성합니다.
                if($stmt->execute())
                {
                    $successMSG = "새로운 사용자를 추가했습니다.";
                }
                else
                {
                    $errMSG = "사용자 추가 에러";
                }



6. 관련 포스팅



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

http://webnautes.tistory.com/829


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

https://webnautes.tistory.com/1159


Android PHP MySQL 예제  - 데이터베이스에 데이터 저장 및 JSON 형식으로 가져오는 예제 프로젝트

http://webnautes.tistory.com/1189  





7. 참고


[1]  http://www.simplifiedcoding.net/php-android-tutorial-part-1/ 


[2]  http://www.simplifiedcoding.net/android-login-and-registration-with-php-mysql/ 


[3]  http://www.tutorialspoint.com/android/android_php_mysql.htm 



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

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

유튜브 구독하기

  1. 이전 댓글 더보기
  2. 민지민지 2020.03.27 15:08

    회원가입 기능을 만들 때 이코드를 참고해서 성공했습니다. 로그인 기능을 구현할 때도 저 코드와 동일하게 작성하면 되는 건가요 ?

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

      유사하게 하면 될듯합니다

    • 민지민지 2020.03.27 16:08

      Undefined index: id

      이 오류가 뜨는데 구글에 찾아보니 php.ini 을 고치라고 나오더라구요. 근데 저는 아파치를 쓰고 있지 않고 PuTTY 라는 프로그램으로 데이터베이스에 연결하고 있는데 혹시 이 오류는 뭔지 아시나요 ㅠㅠ ?

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

      Putty는 터미널 프로그램입니다. 데이터베이스 MySql과 PHP 그리고 Apache를 사용하시고 있을거에요

    • 민지민지 2020.03.27 16:20

      그럼 혹시 php.ini 수정하는 방법 외에 php 코드 안에서 수정하는 방법 아시나요 ? 파일을 건들이는 건 좋은 오류 해결방식이 아니라고 생각되어서요 ,,

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.27 16:21 신고

      변수를 사용하기전에 선언하면 됩니다. 변수 id를 미리 선언해놓고 사용하세요

    • 민지민지 2020.03.27 16:38

      <?php

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

      include('dbcon.php');

      session_start();
      extract($_POST);

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

      $id = '';
      $password='';


      if( (($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit']))||$android)
      {
      $conn = mysqli_connect('localhost', 'LIEYUJIN', '970328', 'CHEMIIFOOD24');
      $conn->set_charset('utf8');

      $user_id=$_POST['id'];
      $user_pw=$_POST['password'];

      echo "<script type='text/javascript'> alert('$user_id'); </script>";


      $query = "select * from user where id = '$user_id'";
      $result = $conn->query($query);

      echo $_SESSION['id'];

      if(mysqli_num_rows($result)==1) {

      너무 길어서 코드는 잘랐는데
      $id = '';
      $password=''; 의 선언위치가 맞나요 ?
      또 똑같은 오류가 떠서요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.27 19:13 신고

      찾아보니 값이 없는 경우를 체크하라네요.. 아래 링크를 참고하세요

      https://stackoverflow.com/a/17870488

    • 민지민지 2020.03.29 14:57

      감사합니다 ! 해결했습니다.

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

      다행입니다~~

  3. ㅎㄹ 2020.04.13 13:42

    안녕하세요. 비슷한 방법으로 리뷰등록 데이터 베이스 삽입 화면을 만들어 보았는데,
    insert버튼을누르면 레이아웃 밑부분 textview에 아무 것도 안뜨고 실제 데이터베이스에도 삽입이 안되더라구요.. 뭐가문제일까요ㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.13 14:42 신고

      로그캣을 사용해 원인을 찾아야합니다. 데이터베이스 접속이 잘되었는지 sql문에 오류는 없는지 등을 봐야 합니다

    • ㅎㄹ 2020.04.16 13:46

      2020-04-16 12:48:27.497 9646-9646/? I/xample.add_dat: Not late-enabling -Xcheck:jni (already on)
      2020-04-16 12:48:27.536 9646-9646/? W/xample.add_dat: Unexpected CPU variant for X86 using defaults: x86
      2020-04-16 12:48:28.099 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
      2020-04-16 12:48:28.099 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
      2020-04-16 12:48:28.099 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
      2020-04-16 12:48:28.099 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
      2020-04-16 12:48:28.099 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
      2020-04-16 12:48:28.690 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
      2020-04-16 12:48:28.691 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
      2020-04-16 12:48:28.700 9646-9646/com.example.add_data W/xample.add_dat: Accessing hidden method Landroid/widget/TextView;->getTextDirectionHeuristic()Landroid/text/TextDirectionHeuristic; (light greylist, linking)
      2020-04-16 12:48:28.846 9646-9646/com.example.add_data D/OpenGLRenderer: HWUI GL Pipeline
      2020-04-16 12:48:28.960 9646-9674/com.example.add_data D/HostConnection: HostConnection::get() New Host Connection established 0xe832b320, tid 9674
      2020-04-16 12:48:28.965 9646-9674/com.example.add_data D/HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_async_unmap_buffer GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_gles_max_version_2
      2020-04-16 12:48:29.015 9646-9674/com.example.add_data I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
      2020-04-16 12:48:29.016 9646-9674/com.example.add_data I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
      2020-04-16 12:48:29.016 9646-9674/com.example.add_data I/OpenGLRenderer: Initialized EGL, version 1.4
      2020-04-16 12:48:29.016 9646-9674/com.example.add_data D/OpenGLRenderer: Swap behavior 1
      2020-04-16 12:48:29.017 9646-9674/com.example.add_data W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
      2020-04-16 12:48:29.017 9646-9674/com.example.add_data D/OpenGLRenderer: Swap behavior 0
      2020-04-16 12:48:29.032 9646-9674/com.example.add_data D/eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 0 0
      2020-04-16 12:48:29.032 9646-9674/com.example.add_data D/EGL_emulation: eglCreateContext: 0xe83042a0: maj 2 min 0 rcv 2
      2020-04-16 12:48:29.155 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:29.208 9646-9674/com.example.add_data D/HostConnection: createUnique: call
      2020-04-16 12:48:29.209 9646-9674/com.example.add_data D/HostConnection: HostConnection::get() New Host Connection established 0xe832b500, tid 9674
      2020-04-16 12:48:29.212 9646-9674/com.example.add_data D/HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_async_unmap_buffer GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_gles_max_version_2
      2020-04-16 12:48:29.212 9646-9674/com.example.add_data E/eglCodecCommon: GoldfishAddressSpaceHostMemoryAllocator: ioctl_ping failed for device_type=5, ret=-1
      2020-04-16 12:48:29.231 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:29.687 9646-9646/com.example.add_data I/Choreographer: Skipped 30 frames! The application may be doing too much work on its main thread.
      2020-04-16 12:48:30.010 9646-9674/com.example.add_data I/OpenGLRenderer: Davey! duration=810ms; Flags=0, IntendedVsync=5457053590672, Vsync=5457553590652, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=5457567332680, AnimationStart=5457567393180, PerformTraversalsStart=5457567713480, DrawStart=5457568208380, SyncQueued=5457569371480, SyncStart=5457595882680, IssueDrawCommandsStart=5457596826080, SwapBuffers=5457682434980, FrameCompleted=5457890316480, DequeueBufferDuration=68000, QueueBufferDuration=7898000,
      2020-04-16 12:48:35.473 9646-9646/com.example.add_data I/AssistStructure: Flattened final assist data: 4088 bytes, containing 1 windows, 14 views
      2020-04-16 12:48:36.394 9646-9646/com.example.add_data I/AssistStructure: Flattened final assist data: 4144 bytes, containing 1 windows, 14 views
      2020-04-16 12:48:37.623 9646-9646/com.example.add_data I/AssistStructure: Flattened final assist data: 4144 bytes, containing 1 windows, 14 views
      2020-04-16 12:48:40.297 9646-9676/com.example.add_data D/NetworkSecurityConfig: No Network Security Config specified, using platform default
      2020-04-16 12:48:40.416 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:40.455 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:40.495 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:40.542 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:40.600 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:40.673 9646-9676/com.example.add_data D/foodchemii24: POST response code - 500
      2020-04-16 12:48:40.717 9646-9674/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe83042a0: ver 2 0 (tinfo 0xe83036b0)
      2020-04-16 12:48:40.898 9646-9646/com.example.add_data D/foodchemii24: POST response -
      2020-04-16 12:49:21.642 9646-9674/com.example.add_data I/OpenGLRenderer: Davey! duration=850ms; Flags=0, IntendedVsync=5508591538680, Vsync=5508591538680, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=5508592641880, AnimationStart=5508592696980, PerformTraversalsStart=5508592724680, DrawStart=5508593241180, SyncQueued=5508593609980, SyncStart=5508674070280, IssueDrawCommandsStart=5508674372380, SwapBuffers=5508700775280, FrameCompleted=5509522059180, DequeueBufferDuration=62000, QueueBufferDuration=207000,
      2020-04-16 13:26:46.297 9646-9674/com.example.add_data I/OpenGLRenderer: Davey! duration=49624ms; Flags=0, IntendedVsync=5514137533970, Vsync=5514137533970, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=5514150310280, AnimationStart=5514150364480, PerformTraversalsStart=5514150392280, DrawStart=5514151057480, SyncQueued=5514151405180, SyncStart=5514152170780, IssueDrawCommandsStart=5514153365180, SwapBuffers=5514171861380, FrameCompleted=5563762850320, DequeueBufferDuration=3469000, QueueBufferDuration=6378000,
      2020-04-16 13:26:47.529 9646-9674/com.example.add_data I/OpenGLRenderer: Davey! duration=1233ms; Flags=0, IntendedVsync=5514632238480, Vsync=5514632238480, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=5514633261580, AnimationStart=5514633311580, PerformTraversalsStart=5514633339280, DrawStart=5514633637380, SyncQueued=5514633921680, SyncStart=5563763252320, IssueDrawCommandsStart=5563877602820, SwapBuffers=5564991824220, FrameCompleted=5564994885620, DequeueBufferDuration=206000, QueueBufferDuration=587000,


      도저히 봐도 해결방법을 모르겠습니다ㅠㅠ

    • ㅎㄹ 2020.04.16 13:46

      2020-04-16 12:48:29.212 9646-9674/com.example.add_data E/eglCodecCommon: GoldfishAddressSpaceHostMemoryAllocator: ioctl_ping failed for device_type=5, ret=-1

      이 줄만 빨간글씨로 뜨긴해요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.16 13:53 신고

      로그캣 내용을 지우고 다시 실행하여 버튼 클릭시 뜨는 로그를 보셔야합니다

    • ㅎㄹ 2020.04.16 14:17

      혹시 에뮬레이터에만 안뜨는거고 실제 스마트폰 단말기에서는 뜨고 삽입될 수도 있을 가능성이 있을까요???

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.16 14:19 신고

      에뮬레이터에서 서버 접속이 안되서 그럴수도 있삽니다

    • ㅎㄹ 2020.04.19 16:08

      2020-04-19 15:59:32.496 14793-14855/com.example.add_data D/foodchemii24: POST response code - 500
      2020-04-19 15:59:32.579 14793-14823/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe8304120: ver 2 0 (tinfo 0xe8303720)
      2020-04-19 15:59:32.648 14793-14823/com.example.add_data D/EGL_emulation: eglMakeCurrent: 0xe8304120: ver 2 0 (tinfo 0xe8303720)
      2020-04-19 15:59:32.757 14793-14793/com.example.add_data D/foodchemii24: POST response -


      버튼 클릭시 로그 이렇게 뜨는데 무ㅓ가 문제일까요....?

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

      응답코드가 500이므로 서버에 문제가 있어 응답을 할 수 없는 상황같습니다. 혹시 php를 모바일의 웹브라우저에서 테스트시 문제없었나요?

    • ㅎㄹ 2020.04.19 16:20

      Error:Failed to connect to/13.209.147.9:80

      스마트폰에서는 이렇게 떳어요ㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.19 16:22 신고

      웹서버가 접속이 왜 안되는지부터 살펴봐야 할듯합니다. 웹서버 로그를 살펴보세요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.19 16:24 신고

      서버가 윈도우에 설치되어 있다면 공용이 아닌 개인 네트워크로 진행해야 합니다

    • ㅎㄹ 2020.04.19 16:41

      감사합니다 해결했씁니다ㅠㅠ
      알고보니까 PHP코드에서 괄호 하나를 빼먹었더라구요... 하 ㅜ 많은 도움 됐습니다!!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.04.19 16:53 신고

      해결되서 다행입니다

  4. ㅎㄹ 2020.04.27 19:51

    안녕하세요 혹시
    레이팅바(별점) 관련 질문드려도 될까요?
    레이팅바를 만들고 데이터베이스 내에 삽입하고 실시간으로 누적되면서 update되게 보여질 수 있을까요?

  5. opppp 2020.05.07 22:36

    질문이있습니다

    제 아이피 주소에서는 데이터값이 넘어가서 db에 저장되는걸 볼수있는데
    다른 사람 아이피주소로 변경하고 php경로도 똑바로 했는데 데이터가 안넘어가요
    어디가 문제일까요 ㅜㅜ

  6. 백원기 2020.05.09 20:49

    먼저 세세한 정보 감사합니다. 원리를 완벽히 이해했습니다.

    질문드릴 사항이 일단 연결, 오류는 없는것 같습니다.

    근데 컬룸에 값을 추가 하는데,
    String postParameters = "name=" + title + "$sex=" + sex + "$place=" + place +
    "$age=" + age + "$doing=" + doing + "$introduce=" + introduce + "$number" + number; 이렇게 작성을 했고

    추가를 하면 오류는 안나옵니다. 근데
    mysql에 select * from tablel; 을 하면 줄은 추가가 되는데 안에 내용이 빈칸으로 저장이 됩니다.

    라즈비안에 서버를 만들고 이용중인데, 보면 연결도 되고 postParameters에 값은 잘 저장에 됩니다. 근데 왜 mysql에 빈칸으로 저장이 되는지 모르겠습니다.

    알려주시면 감사하겠습니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.09 20:52 신고

      php 코드와 android 코드의 post 파라미터 이름이 일치하는지 확인해보세요

  7. 초보자 2020.05.11 14:34

    안녕하세요! 로그인과 회원가입을 구현하려고하는 개발 초보자입니다. 선생님 블로그 많이 참고해서 배우고 있습니다. 감사합니다!
    제가 이번 포스팅을 따라 하다가 안드로이드 부분에서 막혔습니다 ㅠㅠ 로그를 봐도 뭐때문에 안되는지 잘 모르겠습니다.. 밑에 로그가 뜨고 앱이 종료가되는데 혹시 시간 되신다면 읽어주시고 어떤식으로 고치면 좋을지 답변 부탁드립니다!!

    2020-05-11 14:28:30.712 19165-19165/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.cafemoa, PID: 19165
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.cafemoa/com.example.cafemoa.SignupActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setMovementMethod(android.text.method.MovementMethod)' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3488)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3635)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2175)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:237)
    at android.app.ActivityThread.main(ActivityThread.java:7857)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1076)
    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setMovementMethod(android.text.method.MovementMethod)' on a null object reference
    at com.example.cafemoa.SignupActivity.onCreate(SignupActivity.java:51)
    at android.app.Activity.performCreate(Activity.java:7955)
    at android.app.Activity.performCreate(Activity.java:7944)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3463)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3635) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2175) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:237) 
    at android.app.ActivityThread.main(ActivityThread.java:7857) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1076) 

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.11 21:06 신고

      setMovementMethod 메소드를 사용한 TextView가 레이아웃의 리소스와 제대로 연결이 안된듯합니다.

    • 초보자 2020.05.12 16:20

      mTextViewResult = (TextView)findViewById(R.id.textView_main_result);

      mTextViewResult.setMovementMethod(new ScrollingMovementMethod());

      이 부분 말씀하시는거 맞나요?? 똑같이 따라 했는데 어느 부분을 유의해서 봐야 연결을 제대로 시킬 수 있을까요..?

      <TextView
      android:layout_width="match_parent"
      android:layout_height="50dp"
      android:id="@+id/textView_main_result" />

      >

      레이아웃부분은 이렇게 작성했습니다!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.12 20:46 신고

      확인해봤는데 포스트의 코드를 그대로 사용시 에러가 나지 않습니다.

      어딘가에 오타가 난게 아닌가 싶습니다.

    • 초보자 2020.05.12 23:50

      감사합니다 해결되었습니다!! 레이아웃과 연결이 안되어 있었습니다ㅠㅠ 잘 작동 되네요ㅎㅎ 정말 감사합니다 ㅠ

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

      다행입니다

  8. 2020.05.20 02:13

    비밀댓글입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.20 07:55 신고

      사용자가 해당 테이블을 접근할 수 있도록 했나요?

    • 1 2020.05.20 22:51

      GRANT ALL PRIVILEGES ON 데이터베이스이름.* TO '사용자이름'@'localhost' identified by '패스워드';
      이 구문으로 설정했습니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.20 22:56 신고

      mysql 콘솔을 해당 사용자로 로그인되너요?

  9. 2020.05.22 09:38

    웹브라우저로 테스트중에 Failed to connect to the database: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed 이런 오류 메시지가 게속 뜨는데 어떻게 하면 좋을까요 ..ㅠㅠ

  10. rlatjdghk 2020.05.25 08:40

    안드로이드 스튜디오를 실행하면 INSERT까지 되는데 '새로운 사용자를 추가했습니다'라는 문구가 안뜨고 php에도 추가가 안되요ㅜㅜ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.25 08:47 신고

      포스트와 똑같이 진행해보고 바꿔보세요

    • rlatjdghk 2020.05.27 08:32

      똑같이 진행하고 오류도 안나고 php파일로 한 건 저장이 되는데 android에서 하는 것은 please wait까지 진행되고 저장이 안되요ㅠㅠㅠ,,,,,,,,

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.27 08:34 신고

      안드로이드의 웹브라우저에서 php를 실행시켜 문제없나보세요

    • 2020.05.27 08:35

      비밀댓글입니다

    • rlatjdghk 2020.05.27 08:53

      웹브라우저에서 실행이 안되면 어떻게 해야되나욤

    • rlatjdghk 2020.05.27 09:00

      핸드폰으로 연결하니까 Error:failed to connect to/10.0.2.2(port 80)from/172.30.1.8 (port 38842) after 5000ms 오류가 뜨는데 이것도 웹브라우저처럼 php실행만 되면 해결되는 문제인가요?!

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

      pc와 스마트폰이 같은 공유기에 연결안된듯합니다. 확인해보세요

  11. PHP 2020.05.26 17:57

    php파일은 어떻게 생성하는건가요?ㅠ 이클립스 다운받아서 하는건가요?

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

      사용하시는 편집기로 php 파일을 작성하여 php 확장자로 저장하면 됩니다.

  12. 2020.05.30 01:16

    비밀댓글입니다

  13. 사랑합니다 2020.05.30 15:01

    정말감사합니다 형님 충성충성 구독박았습니다!

  14. 2020.06.11 10:40

    비밀댓글입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.11 18:31 신고

      우분투와 안드로이드가 같은 공유기에 연결되어 있어야 합니다

  15. 정유환 2020.06.12 17:09

    안녕하세요.
    데이터베이스에 데이터 입력이 잘 안돼서 질문 드립니다.
    웹에서 php파일을 이용해서 데이터를 입력하면 데이터베이스에 정상적으로 추가가 되는데
    안드로이드에서 데이터 입력을 하니 아무 변화가 없네요..

    protected String doInBackground(String... params) {
    String serverURL = (String)params[0];
    Log.d("URL: ", serverURL);
    String postParameters = "";
    for(int i=0; i<20; ++i) {
    postParameters += "t"+ (i+1) + "=" + t[i];
    if(i!=19)
    postParameters += '&';
    }

    Log.d("A : ",postParameters);

    이 결과로 postParameters 값은
    t1=1&t2=1&t3=1&t4=0&t5=1&t6=1&t7=1&t8=0&t9=1&t10=1&t11=0&t12=0&t13=0&t14=0&t15=0&t16=0&t17=0&t18=0&t19=0&t20=0
    이런 형태로 나옵니다. 코드 나머지 부분은 예제랑 같구요.
    post response code는 200으로 정상적으로 연결은 된 것 같습니다. 혹시 문제점을 알 수 있을까요?? 감사합니다...

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.12 18:41 신고

      서버쪽 로그에 php 접근이 어떻게 처리되었나 우선 살펴보세요

  16. ILLHYHL 2020.06.16 11:27

    kotlin 방식의 코드는 없는건가요? 올려주실수있나요??

  17. 익듀 2020.06.16 13:38

    Warning: include(dbcon.php): failed to open stream: No such file or directory in C:\wamp64\www\insert.php.php on line 6
    Warning: include(): Failed opening 'dbcon.php' for inclusion (include_path='.;C:\php\pear') in C:\wamp64\www\insert.php.php on line 6

    다양한 방법으로 시도 중 인데 혹시 알고있는 오류인가요 ?

  18. sunrise 2020.06.18 01:51

    mAdapter = new UsersAdapter(this, mArrayList);

    PersonalData personalData = new PersonalData();

    이 부분에서 Type parameter cannot be instantiated dilectly 라며 빨간줄이 생깁니다.
    어떻게 해결해야 할까요?

  19. dbmaker 2020.06.23 15:14

    Deprecated: Function get_magic_quotes_gpc() is deprecated in C:\Apache24\htdocs\dbcon.php on line 23
    라고 뜨는데 혹시
    코드를 어떻게 수정해야하는지 알려주실 수 있나요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.23 20:16 신고

      해당 함수가 나중에 제거될수 있다는 메시지입니다. 에러는 아니고 지금 실행하는데에도 문제가 되지는 않지만 나중을 생각하면 해당 함수가 대체되는 함수를 찾아봐야 할듯합니다.

      찾아보니 다음처럼 대체하라고 하네요

      I suggest replacing foreach by "stripslashes_deep":

      Example #2 Using stripslashes() on an array on
      <http://www.php.net/manual/en/function.stripslashes.php>:

      <?php
      function stripslashes_deep($value)
      {
          $value = is_array($value) ?
                      array_map('stripslashes_deep', $value) :
                      stripslashes($value);

          return $value;
      }
      ?>

      This gives:

      <?php
      if((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())    || (ini_get('magic_quotes_sybase') && (strtolower(ini_get('magic_quotes_sybase'))!="off")) ){
          stripslashes_deep($_GET);
          stripslashes_deep($_POST);
          stripslashes_deep($_COOKIE);
      }
      ?>

      출처 링크입니다.

      https://www.php.net/manual/en/function.get-magic-quotes-gpc.php

  20. dsfew 2020.06.30 20:52

    Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'user'@'localhost' (using password: YES)
    해당 에러가 계속 발생하는데, 무엇이 문제일까요? 복사해서 붙여 넣었고, phpMyAdmin에서 확인해도 패스워드 지정 돼 있고 localhost로 host 지정이 다 돼 있는데도 이 문제가 계속 발생하네요....

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.30 20:55 신고

      포스트에서 아래부분을 다시 확인해보세요.

      앞에서 생성했던 데이터베이스를 새로 생성한 사용자가 사용하도록 권한을 부여합니다.  

      mysql> GRANT ALL PRIVILEGES ON 데이터베이스이름.* TO '사용자이름'@'localhost' identified by '패스워드';

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

      데이터베이스에 접근할 수 있는 권한이 제대로 부여안된 상태입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.14 22:44 신고

      늦었지만 답글을 답니다. 3-3을 확인해보세요.

  21. Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.14 18:24 신고

    안드로이드 logcat에서는 문제없이 보내진거 같은데,
    2020-07-14 18:14:14.067 27657-27685/net.**** D/php: POST response code - 200
    2020-07-14 18:14:14.090 27657-27657/net.***** D/php: POST response - fQD2bbb2RfyLr4VTB0yCvn:

    php에서 받질 못합니다ㅠㅠ db랑 연동 할 필요없고 그냥 웹에 띄우기만 하려하는데, 어디가 문제인걸까요?
    이름은 몇번이고 확인을 했습니다 ㅠㅠ
    <?php
    error_reporting(E_ALL);
    ini_set('display_errors',1);

    $token= !empty($_POST['token'])? $_POST['token']:'no';

    echo($token);
    ?>

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.14 18:27 신고

      포스트 코드 기준으로 다음 부분을 확인해보세요

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

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.14 18:32 신고

      InsertData task1 = new InsertData();
      task1.execute("http://" + apacheip + "/token.php", token);

      라고 적어준뒤 그 부분에서는 이렇게 적었습니다!
      String token = (String)params[1];
      String serverURL = (String)params[0];
      String postParameters = "token=" + token;

    • Favicon of https://rrojin.tistory.com BlogIcon rrojin 2020.07.15 10:10 신고

      혹시 php에서 더 적어줘야 할 게 있는건가요?? php파일에 딱 위와 같이 저렇게만 적었습니다 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.15 10:22 신고

      아직 테스트를 못해봤습니다. 급하시면 포스트 코드로 동작 확인한후 원하는 방식으로 수정해보세요

+ Recent posts