1. 수명주기


수명주기는 앱의 상태에 맞추어 기능을 동작시키는 코드를 넣을 수 있도록 해준다.

수명주기는 화면의 상태에 따라 달라지는데 각각의 상태에 따라 자동으로 호출되는 메소드가 다르다.

수명주기를 이용해서, 데이터나 상태 정보를 복구할 수 있다.



2. 액티비티 상태 정보


- Running

  화면 상에 액티비티가 보이면서 실행되어 있는 상태이다.

  액티비티 스택의 최상위에 있으며 포커스를 가지고 있다.


- Paused

  사용자에게 보이기는 하지만 다른 액티비티가 위에 있어 포커스를 받지 못하는 상태이다.

  대화상자가 위에 있어 일부가 가려져 있는 경우에 해당된다.


- Stopped

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



3. 자동으로 호출되는 메서드



화면이 눈에 보이게 되는 과정에서 onCreate, onStart, onResume 메소드가 차례대로 호출된다.

그리고 화면이 없어지는 과정에서 onPause, onStop, onDestroy 메소드가 호출된다.





출처: https://www.edwith.org/boostcourse-android/lecture/17067/

출처: https://www.edwith.org/boostcourse-android/lecture/17066/



1. Serializable & Parcelable


부가데이터

부가데이터는 시스템에서 건드리지 않고 전달만 되며 인텐트 안에 번들(Bundle) 객체가 들어가 있어 

그 안에 데이터를 넣을 때는 putExtra() 메서드, 데이터를 가져올 때는 getExtra() 메소드를 사용한다.


배경

Integer, String과 같은 기본 자료형들이 아닌 아래의 Person과 같이 직접 정의하는 객체가 있다.

1
2
3
4
5
6
public class Person {
    String name;
    int age;
    String phoneNumber;
    String address;
}
cs

Person과 같이 여러 개의 속성이 들어가 있는 객체의 정보들을 전달하려 할 때 Person 클래스 자체를 putExtra(), getExtra()할 수 없다.

즉, 기본 자료형이 아닌 객체는 전달할 수 없기 때문에, 속성마다 일일이 putExtra(), getExtra()를 나누어 넣어야 하는 불편함이 있다. 

그렇기 때문에 이 경우에는 Person 클래스 객체를 바이트 코드로 변환하는 직렬화(Serialization) 작업을 거쳐야 한다.

직렬화: http://qlyh8.tistory.com/97 


직렬화 방법

표준 자바 인터페이스인 Serializable 객체를 이용해 부가데이터로 넣어 전달할 수 있다.

Serializable보다 좀 더 메모리 용량을 적게 차지하는 Android 전용 인터페이스인 Parcelable 객체를 만들어 전달할 수도 있다.


사용방식

ArrayList와 같은 객체들은 이미 Serializable 인터페이스를 구현하고 있으므로 그대로 부가데이터로 추가할 수 있으며, 

그 외에 Person과 같이 직접 정의하는 객체들은 Parcelable 인터페이스를 구현한 후 부가데이터로 추가한다.


성능

Parcelable는 안드로이드 개발에 최적화 되어 있기 때문에 Serializable 보다 속도가 더 빠르다.

Serializable은 Reflection 방법을 사용하여 직렬화를 하는데, Parcelable 은 프로그래머가 직접 직렬화를 구현하기 때문에 빠르다.


** Reflection

Java Class 파일은 Byte code로 컴파일되며, 실행시간에 이 Byte code가 해석되어 실행된다. 

이 Byte code에는 Class에 대한 모든 정보를 포함하고 있다.

Reflection은 구체적인 Class 타입을 알지 못해도, 컴파일된 바이트 코드를 통해 역으로 클래스에 정보를 알아내어

클래스를 사용할 수 있는 기법을 말한다.



2. 실행 결과 화면

    



3. MainActivity.java

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
32
33
34
35
36
37
38
39
40
41
package com.tistory.qlyh8.pracitice;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
 
import java.util.ArrayList;
 
public class MainActivity extends AppCompatActivity {
 
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(), SubActivity.class);
 
                // Serializable 객체 이용
                ArrayList<String> names = new ArrayList<>();
                names.add("aaa");
                names.add("bbb");
                intent.putExtra("names", names);
 
                // Parcelable 객체 이용
                SimpleData data = new SimpleData(100"ccc");
                intent.putExtra("data", data);
 
                startActivityForResult(intent, 101);
            }
        });
    }
}
 
cs



4. SubActivity.java

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.tistory.qlyh8.pracitice;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
import java.util.ArrayList;
 
public class SubActivity extends AppCompatActivity {
 
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
 
        Intent intent = getIntent();
        if(intent != null){
            // ArrayList 와 같은 객체들은 이미 Serializable 인터페이스를 구현하고 있어 그대로 부가데이터로 추가할 수 있다.
            ArrayList<String> names = (ArrayList<String>) intent.getSerializableExtra("names");
            if(names != null){
                Toast.makeText(getApplicationContext(), "리스트 개수: " + names.size(), Toast.LENGTH_LONG).show();
            }
 
            // Parcelable 객체는 Serializable 보다 좀 더 메모리 용량을 적게 차지한다.
            // SimpleData 와 같이 직접 정의하는 객체들은 Parcelable 인터페이스를 구현한 후 부가데이터로 추가한다.
            SimpleData data = intent.getParcelableExtra("data");
            if(data != null){
                Toast.makeText(getApplicationContext(), "SimpleData: " + data.number + ", " + data.message, Toast.LENGTH_LONG).show();
            }
        }
    }
}
 
cs



5. SimpleData.java

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.tistory.qlyh8.pracitice;
 
import android.os.Parcel;
import android.os.Parcelable;
 
// Parcel 은 SimpleData 안에 데이터를 다른 곳에 전달할 때 사용되는 객체이다.
public class SimpleData implements Parcelable {
 
    int number;
    String message;
 
    public SimpleData(int number, String message) {
        this.number = number;
        this.message = message;
    }
 
    // Parcel 에서 SimpleData 안에 들어가 있는 변수를 read 로 복원한다.
    public SimpleData(Parcel src){
        number = src.readInt();
        message = src.readString();
    }
 
    // 역직렬화(바이트 스트림을 원래 데이터 객체로 변환)할 때 사용되어진다.
    public static final Parcelable.Creator CREATOR = new Parcelable.Creator(){
        // 필수 메서드. parcel된 데이터를 다시 원래대로 만들어 준다.
        public SimpleData createFromParcel(Parcel src){
            return new SimpleData(src);
        }
 
        // 필수 메서드. Parcel.createTypeArray()를 호출했을때 불린다.
        public SimpleData[] newArray(int size){
            return new SimpleData[size];
        }
    };
 
    // Parcel의 내용을 기술한다. 
    // FileDescriptor 같은 특별한 객체가 들어가면 이 부분을 통해서 알려줘야한다. 
    // 보통은 0을 리턴해준다.
    @Override
    public int describeContents() {
        return 0;
    }
 
    // SimpleData 를 Parcel 로 바꾼다. (Parcel 안에 데이터를 넣는다.)
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(number);  //number 값을 write
        dest.writeString(message);  // message 값을 write
    }
}
cs



0. 실행 결과 화면


    



1. AndroidManifest.xml


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
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.qlyh8.pracitice">
 
    <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/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 상단 화면 이름을 "서브 화면"으로, 아래와 같이 theme 를 설정하면 대화상자 화면으로 나온다. -->
        <activity
            android:name=".SubActivity"
            android:label="서브 화면"
            android:theme="@style/Base.Theme.AppCompat.Light.Dialog" />
    </application>
 
</manifest>
cs



2. activity_main.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.tistory.qlyh8.pracitice.MainActivity"
    android:gravity="center">
 
   <Button
       android:id="@+id/button"
       android:layout_width="200dp"
       android:layout_height="wrap_content"
       android:text="화면전환" />
 
</LinearLayout>
 
cs



3. activity_sub.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context="com.tistory.qlyh8.pracitice.SubActivity">
 
    <Button
        android:id="@+id/button"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="돌아가기"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
 
cs



4. SubActivity.java


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
package com.tistory.qlyh8.pracitice;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
 
public class SubActivity extends AppCompatActivity {
 
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("name""Tom");
                setResult(Activity.RESULT_OK, intent);
                finish();
            }
        });
    }
}
 
cs


5. MainActivity.java


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.tistory.qlyh8.pracitice;
 
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
public class MainActivity extends AppCompatActivity {
 
    Button button;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(), SubActivity.class);
                //startActivity(intent);
                startActivityForResult(intent, 101);    // 요청코드는 각각의 화면을 구분하는 구분자
 
                // ComponentName 객체를 만들어 설정하는 방법
                // 액티비티를 문자열로만 지정할 수 있어서 동적으로 액티비티를 지정해주고 싶을 때 사용할 수 있다.
                /*Intent intent = new Intent();
                ComponentName name = new ComponentName("qlyh8.tistory.com.pracitice",
                        "qlyh8.tistory.com.pracitice.SubActivity");
                intent.setComponent(name);
                startActivityForResult(intent, 101);*/
            }
        });
    }
 
    // 응답을 받아주는 메서드
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == 101){
            Toast.makeText(getApplicationContext(), "Name: " + data.getStringExtra("name"),
                    Toast.LENGTH_LONG).show();
        }
    }
}
 
cs





출처: https://www.edwith.org/boostcourse-android/lecture/17064/

+ Recent posts