안드로이드 생명주기

 

책 277

 

ctrl + o

 

 

 

 

앱을 처음 켜면

 

 

 

 

 

 

앱을 다시 선택하면

 

 

앱을 끄면

 

체류시간은 onStart부터 onRestart까지로 잡으면됨

 

중요

시작! - onCreate

정지 - onPause

다시돌아올때 - onResume

종료할때 - onDestroy

 

더보기
package com.jaybon.lifecycleex01;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Main_Activity";

    private String downloadData = ""; // 다운로드 데이터로 가정한다
    private String currentState = "";



    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart: ");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause: ");

        currentState = "에너지 50";
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: ");

        Log.d(TAG, "onResume: 현재 에너지는 "+currentState);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
    }

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

        // 다운로드 시작
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for(int i=1; i<4; i++){
                        Thread.sleep(1000);
                        Log.d(TAG, "run: "+i+"초");
                    }
                    downloadData = "다운받은 데이터";
                    Log.d(TAG, "run:  다운로드 종료");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Log.d(TAG, "onCreate: ");
    }
}

 

 

 

------

 

액티비티 매니저 서비스

 

안드로이드 OS

포그라운드 앱 - 선택했을 경우에만 뜸

서비스 앱 (백그라운드 앱) - 서비스는 데몬으로 돈다

 

일반OS는 프로그램을 실행시키면 프로세스가 된다

즉 각각 다 작동되고 있는 상태이다

안드로이드OS는 액티비티 매니저 서비스 라는 앱이 있고 이 것이 모든 앱들을 관리한다

즉 안드로이드는 프로세스가 하나다

다른 앱들을 켜면 액티비티 매니저 서비스에서 관리하게 된다

화면에 보이는 앱들은 작동되고 화면 뒤로 간 앱들은 중지상태가 된다
(중지상태가 된 앱들은 메모리자원을 적게 차지하고 앱의 정보만 들고 있게된다- 이것을 context라고 한다)

contextId

다른앱으로 전환하면 컨텍스트 스위칭이 일어난다

앱들끼리는 매니저를 통해서 통신할 수 있다

 

--------------

앱은 스스로 액티비티 컨텍스트를 관리한다

A1.this

getContext()

getApplicationContext()

---------------

 

--------------------------

TASK - 액티비티가 쌓이는 것

기본적으로 페이지이동시 액티비티를 날리고(finish), 데이터를 남기고 싶을 경우에는 종료를 시키지 않는다

 

TASK 설정에 따라 같은 액티비티가 뜨면 이전의 액티비티를 날릴 수 있다

 

------------------------

 

Intent

Intent를 간단히 생각하면

트럭이라고생각하면된다

출발지와 목적지를 알려주고 내용을 싣는다

번들객체 - 오브젝트를 싣는 곳

 

입력시  put을 사용한다

 

 

 

 

 

shift 따닥

바이트로 바꾼다! (직렬화)

 

 

 

 

 

 

메인액티비티

 

 

안드로이드 내부에서는 데이터 전송시 Bundle을 사용하면 된다

 

--------------------------

 

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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Hello World!" />

    <Button
        android:id="@+id/btn_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Button" />
    
</LinearLayout>

 

 

 

 

MainActivity

package com.example.test;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Main_Activity";

    private TextView tv1;
    private Button btn1;

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

        tv1 = findViewById(R.id.tv_1);
        btn1 = findViewById(R.id.btn_1);

        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tv1.setText("안녕하세요");
            }
        });

    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'App > Android' 카테고리의 다른 글

안드로이드 // TASK  (0) 2020.07.28
안드로이드 // intent / bundle  (0) 2020.07.28
안드로이드 // shared preferences  (0) 2020.07.27
안드로이드 // 생명주기  (0) 2020.07.27
안드로이드 // intent  (0) 2020.07.27

 

 

 

 

 

 

 

https://styled-components.com/docs/basics#installation

 

styled-components: Basics

Get Started with styled-components basics.

styled-components.com

 

 

 

 

 

 

<post key={PK} id={1} title=첫 / >

key는 데이터베이스의 기본키(PK)를 넣자

리액트에 알려줘야한다

기본키를 넣으면 중간에 넣거나 할때 계산이 편하다

반복되는 컴포넌트가 있다면 넣자

 

https://velopert.com/3636

 

누구든지 하는 리액트 7편: 배열 다루기 (1) 생성과 렌더링 | VELOPERT.LOG

이 튜토리얼은 10편으로 이뤄진 시리즈입니다. 이전 / 다음 편을 확인하시려면 목차를 확인하세요. 이번에는 리액트 프로젝트에서 배열을 다루는 방법을 알아보겠습니다. 리액트에서는 배열을

velopert.com

 

 

 

 

액시오스 설치 (통신)

 

 

import React, { Component } from "react";
import Axios from "axios";

class App extends Component {
  state = {
    data: null,
  };

  onClick = () => {
    // 다운받은 json데이터를 자바스크립트 오브젝트로 변환해줌
    Axios.get("https://jsonplaceholder.typicode.com/todos/1") // get방식으로 호출
      // 콜백부분
      .then((resp) => {
        // 프로미스, 밑에꺼 실행하다가 IO가 끝나면 돌아옴
        console.log(resp);
        return;
      });
  };

  render() {
    return (
      <div>
        <h1>클릭하세요</h1>
        <button onClick={this.onClick}>클릭</button>
      </div>
    );
  }
}

export default App;

 

 

 

 

-----------

static default props 검색해보기

-------------

 

프로미스 방식

import React, { Component } from "react";
import Axios from "axios";

class App extends Component {
  state = {
    data: {
      userId: null,
      id: null,
      title: null,
      completed: null,
    },
  };

  onClick = () => {
    const { data } = this.state;
    // 다운받은 json데이터를 자바스크립트 오브젝트로 변환해줌
    Axios.get("https://jsonplaceholder.typicode.com/todos/1") // get방식으로 호출
      // 콜백부분
      .then((resp) => {
        // 프로미스, 밑에꺼 실행하다가 IO가 끝나면 돌아옴
        console.log(resp);
        this.setState({
          data: { data, ...resp.data },
        });
        return;
      });
  };

  render() {
    const { data } = this.state; // 구조분할할당

    return (
      <div>
        <div>아이디: {data.userId}</div>
        <div>제목: {data.title}</div>
        <hr />
        <h1>클릭하세요</h1>
        <button onClick={this.onClick}>클릭</button>
      </div>
    );
  }
}

export default App;

 

 

async 방식

import React, { Component } from "react";
import Axios from "axios";

class App extends Component {
  state = {
    data: {
      userId: null,
      id: null,
      title: null,
      completed: null,
    },
  };

  onClick = async () => {
    const { data } = this.state;
    // 다운받은 json데이터를 자바스크립트 오브젝트로 변환해줌
    let resp = Axios.get("https://jsonplaceholder.typicode.com/todos/1"); // get방식으로 호출
    this.setState({
      data: { data, ...resp.data },
    });
  };

  render() {
    const { data } = this.state; // 구조분할할당

    return (
      <div>
        <div>아이디: {data.userId}</div>
        <div>제목: {data.title}</div>
        <hr />
        <h1>클릭하세요</h1>
        <button onClick={this.onClick}>클릭</button>
      </div>
    );
  }
}

export default App;

 

 

결과

 

--------------

 

 

 

 

runOnUiThread

 

UI쓰레드 = 메인 쓰레드 (onCreate를 실행하는 쓰레드)

다운로드 받을 때에는 무조건 새로운 쓰레드(I/O)

새로운쓰레드로 다운로드 -> 쓰레드 마지막에 콜백

다운로드 다받은 데이터를 메인쓰레드의 변수에서 쓰기 어렵다(다운로드 받는 걸 메인에서 기다리지 않기 때문)

그래서 runOnUiThread 나 핸들러를 사용해야한다.

사용하지 않을려면

메인쓰레드에 함수에 넘겨야하는데 자바는 함수를 넘길 수 없으므로 클래스(인터페이스)를 넘겨야한다

asyncTask를 이용하여 메인에서 다운로드 데이터를 받는 타이밍을 잡아야한다

원리를 이해하고 나서 라이브러리를 사용하자

 

--------------

asyncTask

두잇 안드 490페이지 메서드(doInBackground)

-----------------------

메인쓰레드

이벤트핸들러 쓰레드

-----------------------

다른 쓰레드에서 이벤트핸들러쓰레드를 통해서 메인쓰레드의 이미지를 변경한다

어떻게 하면 다른 쓰레드가 이벤트핸들러에 접근할 수 있을까

1. 쓰레드 안에 runOnUiThread()를 하나더 만들어서 이용 - 핸들러에게 던짐

2. 핸들러를 이용하는 방법 handler.post() (Do it 안드 478페이지)

3.

-----------------------

 

프로그레스 진행 만들기

-----------------------

 

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"
    tools:context=".MainActivity">


    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <Button
        android:id="@+id/btn_execute"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="실행" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="중지" />


</LinearLayout>

 

MainActivity

package com.jaybon.asynctask;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends AppCompatActivity {

    private Button btnExecute, btnStop; //실행 중지버튼
    private ProgressBar progressBar; // 진행바
    private int value = 0; // 진행바의 퍼센테이지
    private Handler handler = new Handler();

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

        mInit(); // 함수 사용할 때 내가 만든 것은 m을 붙이고 오버라이딩은 그대로

        progressBar.setProgress(value);

        mListenser();

    }

    private void mListenser() {
        btnExecute.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() { // 여기다가 데이터변환을 쓰면 안된다(runOnUiThread나 핸들러)
                    @Override
                    public void run() {
                        // runOnUiThread는 잘 안쓰니까 핸들러를 사용하자
                        handler.post(new Runnable() { // 핸들러한테 던지는 타겟을 넣기
                            @Override
                            public void run() {
                                while (true) {
                                    value = value + 5;
                                    progressBar.setProgress(value);
                                    try {
                                        Thread.sleep(500);
                                    } catch (InterruptedException e) {
                                        e.getStackTrace();
                                    }
                                    if(value >= 100){
                                        break;
                                    }
                                }
                            }
                        });
                    }
                }).start();
            }
        });
    }

    private void mInit() {
        btnExecute = findViewById(R.id.btn_execute);
        btnStop = findViewById(R.id.btn_stop);
        progressBar = findViewById(R.id.progressBar);
    }
}

 

결과

진행이 안되고 한번에 쫙 100퍼가 채워진다

쓰레드가 종료되야 핸들러가 실행되기 때문

 

데이터는 변경된다! 다만 UI에 그리는건 핸들러 쓰레드가 끝나야 되는 것!

 

 

------------------------

 

asyncTask로 변경하여 만들기

 

블록지정 부분 삭제

 

 

 

 

 

 

제네릭 값이 전달된다

 

 

 

 

package com.jaybon.asynctask;

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Main_Activity";

    private Button btnExecute, btnStop; //실행 중지버튼
    private ProgressBar progressBar; // 진행바
    private int value = 0; // 진행바의 퍼센테이지
    private Handler handler = new Handler();

    class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {  // 이것이 쓰레드가 됨

        @Override // 타겟 호출 직전
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setProgress(value);
            Log.d(TAG, "onPreExecute: ");
        }

        @Override // 타겟 (run()과 같음)
        protected Integer doInBackground(Integer... integers) { // 스레드 실행시 인수 받기
            Log.d(TAG, "doInBackground: ");

            while (value < 100){

                value = value + 5;
                // 이 값은 onProgressUpdate로 넘어간다
                // 넘어가서 바로 그려짐
                publishProgress(value);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            // 이 값이 onPostExecute의 매개변수로 넘어간다
            return 1; // 정상적으로 수행됐으면 1, 안됐으면 -1
        }

        @Override // UI쓰레드에 그림을 그려주는 메서드
        protected void onProgressUpdate(Integer... values) { // publishProgress 리턴 값 받기
            super.onProgressUpdate(values);
            Log.d(TAG, "onProgressUpdate: ");
            progressBar.setProgress(values[0]); // Integer...는 배열이라서 0번 주소 = Integer[]
        }

        @Override // 타겟 호출 이후
        protected void onPostExecute(Integer integer) { // doInBackground 리턴 값 받기
            // 리턴값 받아서 값에 따라 분기
            super.onPostExecute(integer);
            Log.d(TAG, "onPostExecute: ");
            Toast.makeText(MainActivity.this, "다운로드 완료", Toast.LENGTH_SHORT).show();
        }
    }

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

        mInit(); // 함수 사용할 때 내가 만든 것은 m을 붙이고 오버라이딩은 그대로

        mListenser();

        

    }

    private void mListenser() {

        btnExecute.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new BackgroundTask().execute(); // execute(여기의 값이 doInBackground 의 매개변수로 감)

            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    private void mInit() {
        btnExecute = findViewById(R.id.btn_execute);
        btnStop = findViewById(R.id.btn_stop);
        progressBar = findViewById(R.id.progressBar);
    }
}

 

 

 

 

이렇게 짜면 중지 할 수 없다

중지하려면 전역변수로 잡아줘야한다

 

 

 

 

 

멈추기

 

 

멈추기는 가능하나 다시 실행이 안된다

 

 

중지 재시작

package com.jaybon.asynctask;

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Main_Activity";

    private Button btnExecute, btnStop; //실행 중지버튼
    private ProgressBar progressBar; // 진행바
    private int value = 0; // 진행바의 퍼센테이지
    private  BackgroundTask task;

    class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {  // 이것이 쓰레드가 됨

        @Override // 타겟 호출 직전
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setProgress(value);
            Log.d(TAG, "onPreExecute: ");
        }

        @Override // 타겟 (run()과 같음)
        protected Integer doInBackground(Integer... integers) { // 스레드 실행시 인수 받기
            Log.d(TAG, "doInBackground: ");

            while (isCancelled() == false){

                value = value + 5;

                if(value >= 100){
                    break;
                }

                // 이 값은 onProgressUpdate로 넘어간다
                // 넘어가서 바로 그려짐
                publishProgress(value);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            // 이 값이 onPostExecute의 매개변수로 넘어간다
            return 1; // 정상적으로 수행됐으면 1, 안됐으면 -1
        }

        @Override // UI쓰레드에 그림을 그려주는 메서드
        protected void onProgressUpdate(Integer... values) { // publishProgress 리턴 값 받기
            super.onProgressUpdate(values);
            Log.d(TAG, "onProgressUpdate: ");
            progressBar.setProgress(values[0]); // Integer...는 배열이라서 0번 주소 = Integer[]
        }

        @Override // 타겟 호출 이후
        protected void onPostExecute(Integer integer) { // doInBackground 리턴 값 받기
            // 리턴값 받아서 값에 따라 분기
            super.onPostExecute(integer);
            Log.d(TAG, "onPostExecute: ");
            Toast.makeText(MainActivity.this, "다운로드 완료", Toast.LENGTH_SHORT).show();
        }
    }

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

        mInit(); // 함수 사용할 때 내가 만든 것은 m을 붙이고 오버라이딩은 그대로

        task = new BackgroundTask();

        mListenser();

    }

    private void mListenser() {

        btnExecute.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if(task == null || task.isCancelled() == true){
                    task = new BackgroundTask();
                    task.execute(); // execute(여기의 값이 doInBackground 의 매개변수로 감)
                }


            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                task.cancel(true);


            }
        });
    }

    private void mInit() {
        btnExecute = findViewById(R.id.btn_execute);
        btnStop = findViewById(R.id.btn_stop);
        progressBar = findViewById(R.id.progressBar);
    }
}

 

 

 

--------------

쓰레드종료 interrupt()를 걸면된다. (무조건 sleep 주자)

task.cancel = 잠깐 멈춰서 interrupt()

--------------

 

 

 

 

참고사이트

함수형

https://pro-self-studier.tistory.com/76

 

1. Route 와 파라미터, 쿼리

안녕하세요, 프로독학러 입니다. 이번 포스팅에서는 리액트 라우터에 대해서 좀 더 자세히 알아보도록 하겠습니다. * 포스팅의 내용은 Velopert 님의 리액트 라우터 강의를 복습한 내용이므로 Velop

pro-self-studier.tistory.com

 

클래스형

https://gongbu-ing.tistory.com/44

 

React | Router : URL로 parameter 전송하기

 이전 포스팅에서 SPA의 한계를 극복하고자 라우터를 이용하여 경로에 알맞은 컴포넌트를 불러오는 방법에 대해 공부했다. React | Router : URL로 페이지 접근하기 Single Page Application(SPA) SPA는 서버로

gongbu-ing.tistory.com

 

 

--------------

 

Nav.js

import React from "react";
import { Link } from "react-router-dom";

const Nav = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to="/">홈</Link>
        </li>
        <li>
          <Link to="/about/1">어바웃</Link>
        </li>
        <li>
          <Link to="/profile">프로필</Link>
        </li>
      </ul>
    </div>
  );
};

export default Nav;

 

링크를 걸 네비게이션 바에서 /about/1 로 임의로 1을 넘겨주었다

 

 App.js

import React, { Component } from "react";
import Home from "./page/Home";
import About from "./page/About";
import Profile from "./page/Profile";
import Nav from "./components/Nav";
import { Route } from "react-router-dom";

// exact={true} 는 정확히 주소가 맞아야먄 나오도록 할 수 있다.
class App extends Component {
  render() {
    return (
      <div>
        <Nav />
        <hr />
        <Route path="/" component={Home} exact={true} />
        <hr />
        <Route path="/about/:num" component={About} />
        <hr />
        <Route path="/profile" component={Profile} />
      </div>
    );
  }
}

export default App;

 

Route 시킬 component를 About으로 세팅하고, path="/about/:num"과 같이 변수명을 num으로 지정해준다.

 

About.js

import React from "react";

const About = ({match}) => {
  return (
    <div>
      <h1>ABOUT 페이지 입니다. {match.params.num}</h1>
    </div>
  );
};

export default About;

 

About 함수형 컴포넌트에서 매개변수에 {match}를 적어주고 리턴할 내용에 {match.params.변수명}을 적어주면 입력된다.

 

+ Recent posts