앱을 개발하다보면 페이지를 이동할 때가 많은데,

안하다보면 또 까먹는다... 그렇게 많이 사용했음에도 불구하고...

아마도 너무 습관처럼 사용해서 까먹게 되는 것 같다.

 

페이지의 이동에서는 Intent 메소드를 사용하면 된다.

package com.example.uprotest03;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button title_settings;

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

        // 버튼 액티비티 선언
        title_settings = findViewById(R.id.title_settings);

        // 설정
        title_settings.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intentSetting = new Intent(getApplicationContext(), Settings.class);
                startActivity(intentSetting);
            }
        });

    }
}

 

이런식으로 보통 클릭 이벤트에 섞어서 많이 쓰는 편이다.

만약 클릭 이벤트에 사용하지 않고, MainActivity에서 바로 Intent를 사용해버리면

앱을 시작하자마자 설정해준 화면으로 넘어가버린다ㅋㅋ

 

 

처음으로 emulater로 build하면 다음과 같은 화면을 볼 수 있다.

 

뭔가 되게 보기 싫게 생겼다...

맨 위에 "test1" 이라고 적힌 곳이 타이틀바 이다.

나는 어플을 만들때 타이틀바가 필요없으므로 지워야한다.

 

방법은 간단하게 2가지 정도가 있다.

 

 

 

 

 

 

 

 

1. style.xml 에서 windowNoTiltle 속성 추가하기.

<!-- res\values\style.xml 에 들어가서 windowNoTitle 속성을 true로 추가한다. -->

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Base.Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="windowNoTitle">true</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

 

이건 정말 여러번 써봤는데, 이 style 속성 하나 때문에 오류가 난 적이 한 둘이 아니었다.

에뮬레이터 실행시 어플이 바로 종료되거나 하는 문제가 발생할때가 있다... (원인모름)

가끔 안먹을때도 있던데...

 

 

2. Manifest.xml 에서 NoActionBar 속성 추가하기. (타이틀바+액션바 둘 다 사라진다.)

<!-- Manifext.xml 파일에 android:theme="@style/Theme.AppCompat.NoActionBar" 속성을 추가한다.-->

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.NoActionBar">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

+) 실행결과

 

2번째 방법으로 해보면, 이런 결과가 나온다.

full screen이 된다.

 

2020 Edition...

너무너무 불편하고, 또 오랜만에 안드로이드 스튜디오를 접하는 사람으로써 너무 당황스러웠다.

build는 왜 안되는건지.. 그저 답답할 뿐ㅠ.. 그래서 이전 버전의 안드로이드 스튜디오를 찾아서 설치했다.

 

 

1) 아래의 URL로 접속한다.

https://developer.android.com/studio/archive

 

Android Studio download archives  |  Android 개발자  |  Android Developers

This page provides a download archive of Android Studio releases.

developer.android.com

 

2) I AGREE TO THE TERMS 를 클릭한다.

 

3) 이런 LIST 가 나올텐데, 이건 이전 버전의 Android Studio들

 

그 중에서 지금의 최신 2020 Edition이 아니라, 바로 이전버전을 찾았기 때문에

Android Studio 3.5.1 항목을 다운로드 받았다.

(여러가지 다운받아서 실행해봤는데, 3.6.0 이상 버전은 전부 2020 Edition 인 것 같았다.)

 

노란색으로 표시된 부분을 클릭하면 .exe 파일이 다운받아진다.

 

 

** 해야 할 일

1. select from DB => show Android ()

2. input Android => insert data to DB

 


** use DataBase : MySQL

** Setting ("xampp\htdocts" 에서 php 파일 보관)

use DataBase(DBMS) MySQL(PHPMyAdmin) Environment Windows10
web Server Apatch(localhost, 개이IP) etc 통합 환경 XAMPP 사용

 

여러번 삽질을 해본 결과... 사실 연동이라 함은 깔끔하게 데이터만 뽑아서 가져올법 하지만, 그건 모두 개발자의 몫이다.. 따라서 원하는 데이터가 있다면 먼저 DB에서 php 화면에 데이터를 불러와서 띄운다음에, 그 띄운 글자를 안드로이드에 배열 형태로 가져온다. 그리고 배열에서 '[' 같은 문자를 파싱하고 출력하면 내가 처음에 원하는 것이 나온다...

주로 이런 값 전달은 phpecho "전달할값"$변수명 으로 통한다. 안드로이드에서 쓴 글씨를 DB에 넣지 않고 php 상에서 본다는건... 사실상 좀 까다로운 일 같다.., 될 수 있는지도 모르겠다..

"안드로이드에서 받은 값을 DB에서 넣지 않고 php 상에 띄운다""안드로이드에서 입력한 값을 php로 보내서 echo로 출력하면 그 출력 데이터가 다시 돌아와 안드로이드에서 출력된다" 와 같은 의미였다... 하긴, 동적인 값을 어떻게 php에서 받아서 바로바로 출력해줄 수 있겠어...

 

** 1. select from DB => show Android

1) Select from DB - PHP

안드로이드에서 DB의 값을 출력하고싶다면, 먼저 DB에서 값을 가져와 PHP에 출력하는 작업이 필요하다. 사실상 출력이라기보다는 값전달에 가깝다. PHP 화면상에 DB의 값이 출력되는건 echo 함수로 값을 전달 할 수 밖에 없기 때문에 보여질 수 밖에 없는 것이다..

다음은 DB에서 값을 읽어와 php에 출력하는 코드.

- insertData.php

<?php
    // DB 연동을 시작합니다.
    $con=mysqli_connect("호스트명", "DB ID", "DB PW", "DB 이름");

    // mysqli_connect()에 대한 마지막 호출에 대한 오류 코드 값을 반환한다.
    // echo mysqli_connect() 에서 0은 오류가 발생하지 않았음을 의미한다
    if (mysqli_connect_errno($con)) {
        echo "Failed to connect to MySQL: " . mysqli_connect_error();
    }


    /* select data */
    // 1. 실행할 쿼리문을 작성합니다.
    $selectSQL = "select * from ttest";
    $result = mysqli_query($con, $selectSQL);

    // 출력할 데이터를 저장할 배열변수 선언
    // 데이터는 json-array 형식으로 출력할 것임 (일반적으로 이렇게 함)
    $data = array();
    
    if ($result) {
        while ($row=mysqli_fetch_array($result)) {
            array_push($data,array('컬럼명'=>$row[0],'컬럼명'=>$row[1]));
        }
        header('Content-Type: application/json; charset=utf8');
        $json = json_encode(array("테이블이름"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE);

		echo $json; // => 출력되는 값이 이 코드로 하여금 android로 전송된다..

	} else {
        echo "SQL문 처리중 에러 발생 : ";
        echo mysqli_error($con);
    }

    // DB 연동을 종료 합니다
    mysqli_close($con);
?>

여기서, if 문을 살펴보자

array_push($data,array('컬럼명'=>$row[0],'컬럼명'=>$row[1]));

배열로 선언한 data 변수에 첫번째 컬럼명(row[0]), 두번째 컬럼명(row[1]) 을 연관배열의 형태로 저장한다. 이 부분은 필요하다면 for을 사용해서 더 깔끔하게 코딩할 수 있다.. 나는 그냥 필요한 만큼만 했다.. 여기서 '컬럼명'은 연관배열로 지정해줄 이름일뿐, 굳이 컬럼명을 적지 않아도 된다!!! 대신 컬럼명이 아닌데 컬럼 값을 가지고 있으면, 다른 사람이 볼 때 어떤 값인지.. 잘 알아볼 수 있을까..ㅎ

$json = json_encode(array("테이블이름"=>$data), JSON_PRETTY_PRINT+JSON_UNESCAPED_UNICODE); 

json이라는 변수를 선언하고 아까 data 배열 변수를 json 코드로 인코딩해서 저장했다. 뒤에 있는건 추가적으로 json 배열이 더 예쁘게 내보이고 싶다면 사용하는 옵션이다. 더 필요한 옵션이 있다면 구글링을 하시도록!

 

2) Show Android - Android Programming

- activity_main.xml

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

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/edtText1"
            android:hint="ID"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <EditText
            android:id="@+id/edtText2"
            android:hint="PW"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <LinearLayout
            android:gravity="center"
            android:layout_marginTop="20dp"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Button
                android:id="@+id/insertBtn"
                android:text="insert"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>
    <LinearLayout
        android:orientation="vertical"
        android:layout_marginTop="80dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/txtView"
            android:text="test txt"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>
</LinearLayout>

 

- MainActivity.java

public class MainActivity extends AppCompatActivity {

    private TextView txtView;
    private EditText editText1, editText2;
    Button insertBtn;

    private static String IP = ""; //서버 없이 사용하는 IP가 있다면 저장해서 사용하면 된다.

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

		// 사용할 액티비티 선언
        editText1 = findViewById(R.id.edtText1);
        editText2 = findViewById(R.id.edtText2);
        insertBtn = findViewById(R.id.insertBtn);

		// String url = "http://" + IP + "/php파일명.php";
        String url = "http://" + IP + "/InsertData.php";
        selectDatabase selectDatabase = new selectDatabase(url, null);
        selectDatabase.execute(); // AsyncTask는 .excute()로 실행된다.

    }


    class selectDatabase extends AsyncTask<Void, Void, String> {

        private String url1;
        private ContentValues values1;
        String result1; // 요청 결과를 저장할 변수.

        public selectDatabase(String url, ContentValues contentValues) {
            this.url1 = url;
            this.values1 = contentValues;
        }
        
        @Override
        protected String doInBackground(Void... params) {
            RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
            result1 = requestHttpURLConnection.request(url1, values1); // 해당 URL로 부터 결과물을 얻어온다.
            return result1; // 여기서 당장 실행 X, onPostExcute에서 실행
        }
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            //txtView.setText(s); // 파서 없이 전체 출력
            doJSONParser(s); // 파서로 전체 출력
        }
    }

	// 받아온 json 데이터를 파싱합니다..
    public void doJSONParser(String string) {
        try {
            String result = "";
            JSONObject jsonObject = new JSONObject(string);
            JSONArray jsonArray = jsonObject.getJSONArray("ttest");

            for (int i=0; i < jsonArray.length(); i++) {
                JSONObject output = jsonArray.getJSONObject(i);
                result += output.getString("ed1txt")
                        + " / "
                        + output.getString("ed2txt")
                        + "\n";
            }

            txtView = findViewById(R.id.txtView);
            txtView.setText(result);

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

}

 

- RequestHttpURLConnection.java

public class RequestHttpURLConnection {

        public String request(String _url, ContentValues _params){

            // HttpURLConnection 참조 변수.
            HttpURLConnection urlConn = null;
            // URL 뒤에 붙여서 보낼 파라미터.
            StringBuffer sbParams = new StringBuffer();

            /**
             * 1. StringBuffer에 파라미터 연결
             * */
            // 보낼 데이터가 없으면 파라미터를 비운다.
            if (_params == null)
                sbParams.append("");
                // 보낼 데이터가 있으면 파라미터를 채운다.
            else {
                // 파라미터가 2개 이상이면 파라미터 연결에 &가 필요하므로 스위칭할 변수 생성.
                boolean isAnd = false;
                // 파라미터 키와 값.
                String key;
                String value;

                for(Map.Entry<String, Object> parameter : _params.valueSet()){
                    key = parameter.getKey();
                    value = parameter.getValue().toString();

                    // 파라미터가 두개 이상일때, 파라미터 사이에 &를 붙인다.
                    if (isAnd)
                        sbParams.append("&");

                    sbParams.append(key).append("=").append(value);

                    // 파라미터가 2개 이상이면 isAnd를 true로 바꾸고 다음 루프부터 &를 붙인다.
                    if (!isAnd)
                        if (_params.size() >= 2)
                            isAnd = true;
                }
            }

            /**
             * 2. HttpURLConnection을 통해 web의 데이터를 가져온다.
             * */
            try{
                URL url = new URL(_url);
                urlConn = (HttpURLConnection) url.openConnection();

                // [2-1]. urlConn 설정.
                urlConn.setRequestMethod("POST"); // URL 요청에 대한 메소드 설정 : POST.
                urlConn.setRequestProperty("Accept-Charset", "UTF-8"); // Accept-Charset 설정.
                urlConn.setRequestProperty("Context_Type", "application/x-www-form-urlencoded;cahrset=UTF-8");

                // [2-2]. parameter 전달 및 데이터 읽어오기.
                String strParams = sbParams.toString(); //sbParams에 정리한 파라미터들을 스트링으로 저장. 예)id=id1&pw=123;
                OutputStream os = urlConn.getOutputStream();
                os.write(strParams.getBytes("UTF-8")); // 출력 스트림에 출력.
                os.flush(); // 출력 스트림을 플러시(비운다)하고 버퍼링 된 모든 출력 바이트를 강제 실행.
                os.close(); // 출력 스트림을 닫고 모든 시스템 자원을 해제.

                // [2-3]. 연결 요청 확인.
                // 실패 시 null을 리턴하고 메서드를 종료.
                if (urlConn.getResponseCode() != HttpURLConnection.HTTP_OK)
                    return null;

                // [2-4]. 읽어온 결과물 리턴.
                // 요청한 URL의 출력물을 BufferedReader로 받는다.
                BufferedReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), "UTF-8"));

                // 출력물의 라인과 그 합에 대한 변수.
                String line;
                String page = "";

                // 라인을 받아와 합친다.
                while ((line = reader.readLine()) != null){
                    page += line;
                }

                return page;

            } catch (MalformedURLException e) { // for URL.
                e.printStackTrace();
            } catch (IOException e) { // for openConnection().
                e.printStackTrace();
            } finally {
                if (urlConn != null)
                    urlConn.disconnect();
            }

            return null;
        }
}

 

- NetworkTask.java

public class NetworkTask extends AsyncTask<Void, Void, String> {

        private String url;
        private ContentValues values;

        public NetworkTask(String url, ContentValues values) {

            this.url = url;
            this.values = values;
        }

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

            String result; // 요청 결과를 저장할 변수.
            RequestHttpURLConnection requestHttpURLConnection = new RequestHttpURLConnection();
            result = requestHttpURLConnection.request(url, values); // 해당 URL로 부터 결과물을 얻어온다.

            return result;
        }

}

insert도 비슷하니까 설명 생략하고 그냥 코드 복붙..

 

** 2. input Android => insert data to DB

1) Type input data - Android

- insertData.php (코드 추가함)

<?php

/* insert data */
    // 1. 안드로이드에서 post로 날린 값을 받아 변수에 저장합니다
    $ed1txt = $_POST['ed1txt'];
    $ed2txt = $_POST['ed2txt'];

    // 2. 실행할 쿼리문을 작성합니다. => mysqli_query(실행할 Db, 실행할 query)
    $insertSQL = "insert into ttest (ed1txt,ed2txt) values ('$ed1txt','$ed2txt')";
    $result1 = mysqli_query($con, $insertSQL);

    if ($result1) {
        echo "Success!!";
    } else {
        echo "Fail insert data to Database...";
    }
    
    ?>

 

2) Insert data to DB - PHP

- MainActivity.java (코드 추가함)

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

        insertBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                insertoToDatabase(editText1.getText().toString(),editText2.getText().toString());
            }
        });

    }

    private void insertoToDatabase(final String ed1, String ed2) {
        class InsertData extends AsyncTask<String, Void, String> {
            ProgressDialog loading;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                loading = ProgressDialog.show(MainActivity.this, "Please Wait", null, true, true);
            }
            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                loading.dismiss();
                //Log.d("Tag : ", s); // php에서 가져온 값을 최종 출력함
                Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
            }
            @Override
            protected String doInBackground(String... params) {

                try {
                    String edt1Text = (String) params[0];
                    String edt2Text = (String) params[1];

                    String link = "http://"+cafeIP+"/InsertData.php";
                    String data = URLEncoder.encode("ed1txt", "UTF-8") + "=" + URLEncoder.encode(edt1Text, "UTF-8");
                    data += "&" + URLEncoder.encode("ed2txt", "UTF-8") + "=" + URLEncoder.encode(edt2Text, "UTF-8");

                    URL url = new URL(link);
                    URLConnection conn = url.openConnection();

                    conn.setDoOutput(true);
                    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(conn.getOutputStream());
                    outputStreamWriter.write(data);
                    outputStreamWriter.flush();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

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

                    // Read Server Response
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                        break;
                    }
                    Log.d("tag : ", sb.toString()); // php에서 결과값을 리턴
                    return sb.toString();

                } catch (Exception e) {
                    return new String("Exception: " + e.getMessage());
                }
            }
        }
        InsertData task = new InsertData();
        task.execute(ed1,ed2);
    }

 

 


** 헉 대박 이거 잊으면 안됨 꼭 해야함

** manifest 셋팅

- AndroidManifest.xml

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

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

    <application
        android:usesCleartextTraffic="true">
    </application>

</manifest>

 

1. 인터넷 퍼미션

2. thread 오류가 나도 계속 진행하게함.

 


 

 

+ Recent posts