티스토리 뷰

 액티비티는 안드로이드 앱의 네가지 기본 구성 요소(액티비티, 서비스, 브로드캐스트 수신자, 내용 제공자) 중 하나

 앱에서 화면은 액티비티로 구현. 즉, 화면을 필요에 따라 띄우거나 닫는 과정은 액티비티를 전환하는 것과 같음

 

따라서 액티비티는 좋은 앱을 만들기 위해서 꼼꼼하게 공부해야한다!

 

 

# 이 어플이 가지고 있는 액티비티를 시스템이 어떻게 알까?

안드로이드 시스템은 AndroidManifest.xml 파일에서 앱의 네가지 기본 구성 요소에 대한 정보를 확인함.

따라서, 새로운 액티비티를 만들어 앱에 추가한다면 매니페스트 파일에 해당 액티비티 정보를 추가해야 함.

 

(1) app에서 오른쪽 마우스 > New > Activity 로 액티비티를 추가하면 자동으로 매니페스트 파일에도 추가

(2) xml파일과 java파일을 따로따로 만들었으면 반드시 매니페스트 파일에 액티비티를 추가해야 함!

 

 

# 액티비티에서 다른 액티비티를 어떻게 띄울 수 있을까?

시스템이 액티비티 정보를 가지고 있으니까 시스템한테 '나 이 액티비티 띄울래!'라고 명령해야함. 이런 명령, 데이터를 시스템에게 전달하기 위해선 인텐트를 사용! (인텐트에 대해 자세히 알고 싶다면)

 

결론, startActivity(), startActivityForResult() 메서드에 인텐트를 넣어서 호출하면 새로운 액티비티를 띄울 수 있음!

(startActivity()는 단순히 액티비티를 띄울 때 사용하고, 만약 이전 액티비티와 데이터를 주고 받고 싶으면 startActivityForResult()사용)

아직 인텐트가 낯설어도, 일단 화면 전환을 해보자!

 

코드설명) 메인 액티비티 버튼 클릭 → 메뉴 액티비티 띄움 → 메뉴 액비티비 버튼 클릭 → 부가데이터와 함께 이전 액티비티로 응답 → 메인 액티비티에서 응답을 받아서 처리

//MainActivity.java
public class MainActivity extends AppCompatActivity {
    public static final int REQUEST_CODE_MENU = 101; //메뉴 액티비티만의 고유한 요청코드

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

        Button button = findViewById(R.id.button); //메인 액티비티 버튼
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(), MenuActivity.class); //현재 액티비티와 띄우고 싶은 액티비티를 파라미터로 인텐트 정의!
                startActivityForResult(intent, REQUEST_CODE_MENU); //새로운 액티비티 띄우기!
            }
        });

    }

    //응답이 왔을 때 자동으로 호출 (requestCode로 어떤 액티비티가 보낸 응답인지 확인!)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CODE_MENU) {
            //MenuActivity가 보낸 것이라면
            Toast.makeText(getApplicationContext(),
                    "onActivityResult 메소드 호출됨. 요청 코드 : " + requestCode +
                            ", 결과 코드 : " + resultCode, Toast.LENGTH_LONG).show();
            if (resultCode == RESULT_OK) {
            	//정상적으로 응답이 처리되었으면
                String name = data.getStringExtra("name");
                Toast.makeText(getApplicationContext(), "응답으로 전달된 name : " + name,
                        Toast.LENGTH_LONG).show();
            }
        }

    }
}
//MenuActivity.java
public class MenuActivity extends AppCompatActivity {

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

        Button button = findViewById(R.id.button); //메뉴 액티비티 버튼
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("name", "mike"); //인텐트에 부가 데이터 넣기!
                setResult(RESULT_OK, intent); //이전 액티비티(여기선 메인)로 인텐트를 전달

                finish(); //현재 액티비티 없애기
            }
        });

    }
}

 

 

# 액티비티가 인플레이션 되어있는데도 계속 startActivity()로 중복된 액티비티를 호출하면 어떻게 될까?

✔ 동일한 액티비티가 메모리에 여러 개 만들어짐 (비효율)

액티비티는 액티비티 매니저라는 객체에 의해 '액티비티 스택'이라는 것으로 관리. 따라서 액티비티 중복 호출 시 동일한 액티비티가 스택에 여러 개 들어감 → 동시에 데이터를 여러 번 접근하거나 리소스를 여러 번 사용하는 문제가 발생할 수 있음

 

 → 해결책은 플래그(Flag)!

 

 

# 대표적인 플래그는 어떤 것일까?

- FLAG_ACTIVITY_SINGLE_TOP : 액티비티를 생성할 때 이미 생성된 액티비티가 있으면 그 액티비티를 그대로 사용! (onCreate()가 호출되지 않음. 대신 onNewIntent()로 새 액티비티를 위한 인텐트를 전달 받을 수 있음)

- FLAG_ACTIVITY_SINGLE_NO_HISTORY : 처음 이후에 실행된 액티비티는 액티비티 스택에 추가되지 않음.

- FLAG_ACTIVITY_CLEAR_TOP : 이 액티비티 위에 다른 액티비티를 모두 종료(ex.홈 화면)

 

 

# 플래그는 어떻게 사용할까?

(1) AndroidManifest.xml

<activity android:name=".MainActivity"
		android:launchMode="singleTop"> //FLAG_ACTIVITY_SINGLE_TOP과 동일
...
</activity>

(2) java 소스코드에서 Intent.addFlags() 또는 Intent.setFlags() 사용

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //기존의 flag들에 새로운 flag를 추가
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); //기존의 flag들을 삭제하고 설정

* 플래그는 태스크를 관리할 때도 사용! (참고하면 좋을 글)

 

 

# 액티비티 생명주기?

액티비티는 처음 실행될 때 메모리에 만들어지는 과정부터 시작해서 실행과 중지, 그리고 메모리에서 해제되는 여러 과정의 상태 정보를 갖고 있으며, 이러한 상태정보가 변화하는 것을 액티비티의 '생명주기'라고 함.

 

 

 

 

 

(1) 액티비티의 대표적인 상태 정보

실행 : 화면 상에 액티비티가 보이면서 실행 중. 액티비티 스택의 최상위. 포커스O

일시 정지 : 사용자에게 보이지만 다른 액티비티가 위에 있어 포커스X

중지 : 다른 액티비티에 의해 완전히 가려져 보이지 않는 상태

 

 

 

 

 

 

 

(2) 액티비티의 상태 메서드

onCreate

: 액티비티가 처음에 만들어 졌을 때 호출. 화면에 보이는 뷰들의 일반적인 상태를 설정. 이전 상태가 저장되어 있는 경우에는 번들 객체를 참조하여 이전 상태 복원.

onStart

: 액티비티가 화면에 보이기 바로 전에 호출. 액티비티가 화면 상에 보이면 이 메서드 다음에 onResume() 호출하고 액티비티가 화면에서 가려지게 되면 이 메서드 다음에 onStop() 호출

onResume

: 액티비티가 사용자와 상호작용하기 바로 전에 호출

on Restart

: 액티비티가 중지된 이후에 호출되는 메서드로 다시 시작되기 바로 전에 호출. 이 메서드 다음에는 항상 onStart() 호출

onPause

: 또 다른 액티비티를 시작하려고 할 때 호출. 액티비티가 소멸되거나 또 다른 액티비티가 화면을 가릴 때 호출

onStop

: 액티비티가 사용자에게 더 이상 보이지 않을 때 호출. 액티비티가 소멸되거나 또 다른 액티비티가 화면을 가릴 때 호출. 액티비티가 이 상태에 들어가면 시스템은 액티비티를 강제 종료할 수 있음

onDestroy

: 액티비티가 소멸되어 없어지기 전에 호출. 이 메서드는 액티비티가 받는 마지막 호출. 액티비티가 앱에 의해 종료되거나(finish 메서드로) 시스템이 강제로 종료시키는 경우에 호출될 수 있음

 

 

# 앱이 일시정지, 중지되었을 때 데이터를 어떻게 저장하고 복원할까?

(1) onPause(), onResume()를 구현

public class MainActivity extends AppCompatActivity {
    EditText nameInput;

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

        nameInput = findViewById(R.id.nameInput);
        
        ...

        Toast.makeText(this, "onCreate 호출됨", Toast.LENGTH_LONG).show();
        println("onCreate 호출됨");
    }

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

        Toast.makeText(this, "onPause 호출됨", Toast.LENGTH_LONG).show();
        println("onPause 호출됨");

        saveState(); //데이터 저장
    }

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

        Toast.makeText(this, "onResume 호출됨", Toast.LENGTH_LONG).show();
        println("onResume 호출됨");

        restoreState(); //데이터 복원
    }

    public void println(String data) {
        Toast.makeText(this, data, Toast.LENGTH_LONG).show();
        Log.d("Main", data); //Main 태그를 이용해 Log를 쉽게 볼 수 있음.
    }

    protected void restoreState() {
        //간단한 데이터를 저장, 복원 할 때 사용하는 SharedPreferences 객체
        SharedPreferences pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
        if ((pref != null) && (pref.contains("name"))) {
            String name = pref.getString("name", "");
            nameInput.setText(name);
        }
    }

    protected void saveState() {
        SharedPreferences pref = getSharedPreferences("pref", Activity.MODE_PRIVATE); //앱 내부에 파일을 하나 만듬
        SharedPreferences.Editor editor = pref.edit();
        editor.putString("name", nameInput.getText().toString()); //저장하려는 데이터 설정
        editor.commit(); //실제 저장
    }

    protected void clearState() {
        SharedPreferences pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        editor.clear();
        editor.commit();
    }
}

 

(2) 액티비티를 중지시키기 전에 호출되는 onSaveInstanceState() 사용하여 데이터를 임시 저장하고 onCreate(), onRestoreInstanceState()로 저장했던 데이터 전달 (앱이 강제 종료되거나 비정상 종료된 이후에 앱이 재실행되었을 때도 그 상태 그대로 보일 수 있음)

 


출처

Do it! 안드로이드 앱 프로그래밍(개정8판)

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함