반응형

 여러분의 앱을 디자인할 때 넓은 화면 사이즈를 지원하기 위해서, 가능한 화면의 크기를 기반으로 사용자경험(User Experence: UX)을 최적화 하기 위해 다른 레인아웃 구성에 여러분의 프레그먼트를 재사용할 수 있습니다.


 예를 들어, 핸드폰 같은 단말기(handset device)에서는 단일창의 UI 에 대해 한번에 하나의 프레그먼트를 보여주는 것이 적적할 지도 모릅니다. 반대로, 여러분은 사용자에게 더 많은 정보를 보여주기 위해 광범위한 화면크기(wider screen size)를 가진 테블릿(Tablet) 에서 나란히(side by side) 프레그먼트들을 설정하고 싶을 수도 있습니다.




 


그림 1. 다른 화면 크기를 가진, 같은 액티비티의 다른 구성을 보여주는 2개의 프레그먼트들. large 화면에서, 프레그먼트들은 양쪽에 나란히(side by side) 맞추어져 있지만, 핸드폰 같은 단말기(handset device)에서는, 사용자에 탐색 이동(navigates)에 따라 한번에 하나의 프레그먼트에 맞도록 각 각 따로 배치되어야만 합니다.


 FragmentManager 클래스는 여러분이 동적인 사용자 경험(Dynamic experence)을 만들기 위해 실행중에 액티비티에 프레그먼트를 추가, 제거, 재배치 할 수 있도록 하는 메소드를 제공합니다. 



실행중에 액티비티에 프레그먼트 추가하기

(Add a Fragment to an Activity at Runtime)

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

 레이아웃 파일 안에 액티비티에 대한 프레그먼트들을 정의(이전 포스트에서 <fragment> 요소로 소개했었던) 하는 대신에 여러분은 액티비티가 실행하는 동안 프레그먼트를 추가할 수 있습니다. 이 방법은 액티비티가 살아있는 동안에 프레그먼트들을 변경할 계획이 있을 때 필요합니다.


 프레그먼트를 추가하거나 제거하는 등의 작업을 실행하기 위해서는, FragmentTransaction을 만들기 위해 FragmentMananger를 사용해야만 합니다. FragmentTransaction 은 추가(add), 제거(remove), 재배치(replace), 다른 프레그먼트 트랜젝션(fragment transactions)들을 실행하는 API 들을 제공합니다.


 만약 여러분의 액티비티가 프레그먼트를 제거하고 재배치 한다면, 여러분은 반드시 액티비티의 onCreate() 메소드에서 프레그먼트(들)을 초기화 하도록 추가해야 만 합니다.


 프레그먼트(들)을 처리할 때(특히, 실행중에 프레그먼트들을 추가할 때) 중요한 법칙은 여러분의 액티비티 레이아웃이 프레그먼트를 삽입할 있는 컨테이너 뷰(container View)를 포함하고 있어야만 한다는 것입니다.


  아래의 레이아웃은 이전 포스트에서 보여줬던 한번에오직 한 개의 프레그먼트만 보여주는 레이아웃의 대체 리소스입니다. 다른 프레그먼트와 함께 프레그먼트를 재배치 하기 위해서 액티비티의 레이아웃은 프레그먼트의 컨테이너(container)로서 비어있는 FrameLayout 을 포함하고 있습니다.


이전 포스트에서 만들었던 레이아웃 파일과 같은 이름이라는 것을 주의하시기 바랍니다. 레이아웃 디렉토리에 larger 규정 크기가 없다면 이 레이아웃은 larger 보다 작은 단말기 화면에서 사용되어 집니다. 왜냐하면 화면은 같은 시간에 프레그먼트들 모두들 맞추지 않기 때문입니다.


res/layout/news_articles.xml :

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/fragment_container"

    android:layout_width="match_parent"

    android:layout_height="match_parent" />


 여러분의 액티비티 안에서, Support Library APIs 를 사용한 FragmentManager를 얻기 위해 getSupportFragmentManager 를 호출합니다. 그런다음 FragmentTransaction 을 만들기 위해 beginTransaction() 을 호출하고 add()를 호출해서 fragment 를 추가합니다.


 여러분은 같은 FragmentTransaction을 사용하여 액티비티에 대한 다중 프레그먼트 트랜잭션(fragment transaction)을 실행할 수 있습니다. 여러분이 변경사항을 만들 준비가 되었다면 반드시 commit() 메소드를 호출해야만 적용됩니다.



아래의 예제는 이전 레이아웃에 프레그먼트를 추가하는 방법입니다.

 import android.os.Bundle;

import android.support.v4.app.FragmentActivity;


public class MainActivity extends FragmentActivity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.news_articles);


        // Check that the activity is using the layout version with

        // the fragment_container FrameLayout

        if (findViewById(R.id.fragment_container) != null) {


            // However, if we're being restored from a previous state,

            // then we don't need to do anything and should return or else

            // we could end up with overlapping fragments.

            if (savedInstanceState != null) {

                return;

            }


            // Create a new Fragment to be placed in the activity layout

            HeadlinesFragment firstFragment = new HeadlinesFragment();

            

            // In case this activity was started with special instructions from an

            // Intent, pass the Intent's extras to the fragment as arguments

            firstFragment.setArguments(getIntent().getExtras());

            

            // Add the fragment to the 'fragment_container' FrameLayout

            getSupportFragmentManager().beginTransaction()

                    .add(R.id.fragment_container, firstFragment).commit();

        }

    }

}


 실행중에 FrameLayout 컨테이너(container)에 추가되어진 프레그먼트이기 때문에( <fragment> 태그로 액티비티의 레이아웃에 정의한 것 대신에) 액티비티는 프레그먼트를 제거하고 다른 것들과 함께 재 배치 할 수 있습니다.




다른 프레그먼트와 함께 프레그먼트 재배치하기


( Replace One Fragment with Another)

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

 프레그먼트를 재배치(replace)하는 작업은 추가(add)하는 작업과 비슷합니다. 단지 add() 대신에 replace() 를 사용하면 됩니다.


 여러분이 프레그먼트를 재배치 하거나 제거하는 등의 프레그먼트 트랜잭션들을 실행할 때, 사용자가 종종 뒤로가기(navigate backward)를 하거나 변경을 "취소(undo)" 하면 적절히 동작하도록 해야 한다는 점을 유의하시기 바랍니다. 사용자가 프레그먼트 트랜잭션들을 통해 뒤로가기(navigate backward)를 동작하려면 여러분은 반드시 FragmentTransaction을 커밋(commit)하기 전에addToBackStack()을 호출해야만 합니다.


 Note: 여러분이 프레그먼트를 제거(remove)하거나 재배채(replace) 하고 back 스택(stack)에 추가했을 때, 제거된 프레그먼트는 정지(stoped)됩니다(파괴되지 않습니다. Not Destroyed). 만약 사용자가 프레그먼트를 복구하기 위해 뒤로가기(navigate backward)를 한다면, 프레그먼트는 다시 시작합니다. 만약 여러분이 백 스택(back stack)에 추가하지 않는 다면, 프레그먼트는 제거(remove)되거나 재배채(replace)될 때 파괴(Destroyed) 됩니다.



 다른 프레그먼트와 함께 프레그먼트를 재배치하는 예제입니다 :

 // Create fragment and give it an argument specifying the article it should show

ArticleFragment newFragment = new ArticleFragment();

Bundle args = new Bundle();

args.putInt(ArticleFragment.ARG_POSITION, position);

newFragment.setArguments(args);


FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();


// Replace whatever is in the fragment_container view with this fragment,

// and add the transaction to the back stack so the user can navigate back

transaction.replace(R.id.fragment_container, newFragment);

transaction.addToBackStack(null);


// Commit the transaction

transaction.commit();


 addToBackStack() 메소드는 트랙잭션에 대한 유일한 이름을 지정한 하나의 옵션 문자열(string) 파라미터를 가집니다. 이 이름은 여러분이 FragmentManager.BackStackEntry APIs 를 사용하는 향샹된 프레그먼트(advanced fragment) 명령들을 실행하는 경우를 제외하고는 필요하지 않습니다.       

반응형
반응형

 여러분은 액티비티의 모듈 섹션(modular section)으로서 프레그먼트를 생각할 수 있습니다. 이 프레그먼트는 자신의 라이프사이클(lifecycle)을 가지며, 입력 이벤트(Input Events)도 받을 수 있고, 액티비티가 실행하는 동안에 추가하거나 제거할 수도 있습니다.( 여러분이 다른 액티비티에서 재사용할 수 있는 "sub Activity" 같은 종류). 이번 시간에는 Support Library 를 사용하여 Fragment 클래스를 상속(확장)하는 방법을 보여드립니다. Support Library 를 사용함으로서 여러분의 앱은 Android 1.6 처럼 낮은 버전에의 시스템에서 구동하고 있는 단말기에서도 여전히 호환될 수 있도록 할 수 있습니다. 


 Note : 만약 여러분이 minimum API level 을 11버전 이상을 요구하도록 결정했다면, Support Library 를 사용할 필요가 없으며,Fragment 클래스와 관련된 APIs을 이용하여 프레그먼트의 생성을 대신하도록 할 수 있습니다. 단지, 이번 시간에는 Support Library로부터 APIs 을 사용하도록 초점을 맞추었기 때문에, 몇가지 플랫폼 안에 포함된 버전과는 조금 다른 API 이름과 특정 패키지 표시가 사용될 것임을 알아주시기 바랍니다.


 여러분은 이번 장을 시작하기 전에, Support Library 를 사용하여 Android 프로젝트를 만들도록 해야만 합니다. 만약 여러분이 이전에Support Library 를 사용하지 않았다면, 여러분의 프로젝트에 개발자 사이트의 Support Library Setup 문서를 보고 따라해서 v4 library를 사용하도록 설정하시기 바랍니다. 어쨋든, 여러분은 v7 appcompat library 를 사용하여 여러분의 액티비티안에 액션바(actiob bar)를 포함하고 있어야 합니다. 이로 인해 Fragments APIs 를 포함하면서 Android 2.1(API level 7) 버전과도 호환되도록 할 수 있습니다.



프레그먼트 클래스 만들기(Create a Fragment Class)

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

 하나의 프레그먼트를 만들기 위해 Fragment 클래스를 상속(확장)하고 나서 , Activity 클래스에서 여러분이 했던 방법과 비슷하게 앱의 로직을 작성하기 위해 주요한 라이프사이클(lifecycle) 메소드들을 오버라이드(override)합니다.


 한가지 다른점은 프레그먼트를 만들때 레이아웃을 정의하기 위해 onCreateView() 콜백(callback) 메소드를 사용해야만 한다는 것입니다. 사실, 이것이 프레그먼트를 실행하는데 필요한 유일한 콜백(callback) 입니다. 아래 프레그먼트의 레이아웃을 지정하는 간단한 프레그먼트 예제가 있습니다.


 import android.os.Bundle;

import android.support.v4.app.Fragment;

import android.view.LayoutInflater;

import android.view.ViewGroup;


public class ArticleFragment extends Fragment {

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

        Bundle savedInstanceState) {

        // Inflate the layout for this fragment

        return inflater.inflate(R.layout.article_view, container, false);

    }

}


단지 액티비티처럼, 프레그먼트(fragment)가 액티비티로부터 추가되거나 제거되기도 하고, 액티비티의 라이프사이클 상태들 사이의 전환과 같은 상태를 관리할 수 있으려면 다른 라이프사이클(lifecycle) 콜백(callback) 메소드들을 구현하면 됩니다.


 fragment 라이프사이클(lifecycle)과 콜백(callback) 메소드에 대한 더 많은 정보를 원한다면, 개발자 사이트의 Fragments 가이드를 참고하시기 바랍니다.






XML을 사용하여 Activity에 프레그먼트 추가하기

Add a Fragment to an Activity using XML )

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

 UI 컴포턴트(components) 모듈로서 프레그먼트를 재사용하는 동안, 각 각의 Fragment 인스턴스(instance)는 반드시 부모로서FragmentActivity와 조합하여야만 합니다. 여러분은 액티비티 레이아웃 XML 파일안에 프레그먼트(fragment)를 정의함으로서 조합할 수 있습니다.


 Note : FragmentActivity API level 11 버전 이전의 시스템에서 프레그먼트를 처리하기 위해 Support Library에서 제공하는 특별한 액티비티입니다. 만약 여러분이 지원하는 가장 낮은 버전이 API level 11 이상이라면, 여러분은 정규 Activity를 사용할 수 있습니다.


아래는 "large"로 결정된 단말기 화면에서 하나의 액티비티에 두개의 프레그먼트를 추가한 레이아웃파일의 예제 입니다.


res/layout-large/news-articles.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="horizontal"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent">


    <fragment android:name="com.example.android.fragments.HeadlinesFragment"

              android:id="@+id/headlines_fragment"

              android:layout_weight="1"

              android:layout_width="0dp"

              android:layout_height="match_parent" />


    <fragment android:name="com.example.android.fragments.ArticleFragment"

              android:id="@+id/article_fragment"

              android:layout_weight="2"

              android:layout_width="0dp"

              android:layout_height="match_parent" />


</LinearLayout>

Tip : 다른 화면 사이즈에 대한 레이아웃 만들기에 대한 자세한 내용은 앞에 포스팅한 "다른 크기, 해상도, 밀도의 화면들 지원하기(Supporting Difference Screens) "를 보시기 바랍니다.


그런다음 여러분에 액티비티에 위의 레이아웃을 적용합니다.

import android.os.Bundle;

import android.support.v4.app.FragmentActivity;


public class MainActivity extends FragmentActivity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.news_articles);

    }

}

 

만약 v7 appcompat library를 사용한다면, 여러분의 액티비티는 FragmentActivity의 서브클래스(sub class)인 ActionBarActivity를 상속(확장) 해야만 합니다. ( 추가 정보는 앞전 포스팅의 "Action Bar(액션바) 추가하기"를 참고하세요)



 Note : 여러분이 XML 파일안에서 프레그먼트(fragment)를 정의하여 액티비티 레이아웃에 추가했을 때는 실행중에 프레그먼트(fragment)를 제거할 수 없습니다. 만약 사용자와 상호작용(interaction) 중에 프레그먼트의 안밖을 전환할 계획이라면, 여러분은 액티비티가 처음 시작될 때 액티비티에 프레그먼트를 추가해야만 합니다. 다음포스트에서 보여드릴 겁니다.  

반응형
반응형

 안드로이드에서 동적(Dynamic)이면서 다중 창(multi-pane)을 가진 사용자 인터페이스(User Interface : UI )를 만들기 위해서는, 여러분의 액티비티들의 안밖으로 전환할 수 있는 모듈로 동작하는 액티비티와 UI 컴포넌트를 캡슐화 할 필요가 있습니다. 여러분은Fragment 클래스로 이 모듈들을 만들 수 있습니다. 이 클래스는 본인만의 라이프사이클을 가지며 이를 관리하고 또한 자신만의 레이아웃을 정의할 수 있는 객체로 마치 중첩된 다중 액티비티처럼 동작합니다.


 fragment는 자신이 가지고 있는 레이아웃을 정의할 때, 서로 다른 화면사이즈( 작은 화면사이즈에서는 하나의 프레그먼트를 보여주고 큰 화면에서는 두개 이상을 보여줄줘야 할 수 도 있습니다.)에 대한 레이아웃 구성요소를 수정하기 위해 하나의 액티비티 안에 서로 다른 프레그먼트들(fragments)을 다르게 결합하도록 구성할 수 있습니다.


 이번 강좌는 여러분이 서로 다른 화면 사이즈들을 가진 단말기에 대해 프레그 먼트(fragment)를 이용하여 동적(Dynamic)인 사용자 경험(User experience : UX)를 만들고 앱의 사용자 경험(User experience : UX)을 최적화 하는 방법을 보여드리고자 합니다. Android 1.6 처럼 오래된 버전에서 구동중인 단말기도 지속적으로 지원하도록 하는 할 것입니다.



Lessons

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

Fragment 생성하기(Create a Fragment)

 fragment를 만드는 방법과 콜백(callback) 메소드들내에서 기본적인 동작들을 구현하는 방법을 학습합니다.


유연한 UI 만들기(Building a Flexible UI)

 서로 다른 화면에 대해 서로 다른 fragment 구성요소를 제공하는 레이아웃을 가질 수 있도록 앱을 구축하는 방법을 학습합니다.


다른 프레그먼트들과 통신하기(Communicating with Other Fragments)

 하나의 프레그먼트(fragment)에서 다른 액티비티 또는 다른 프레그먼트들로의 통신경로를 설정하는 방법을 학습합니다.

반응형
반응형

 액티비티에서 finish() 를 호출하여 액티비티를 소멸하는 신호를 주거나 사용자가 Back 버튼을 눌렀을 때와 같이, 일반적으로 앱을 파괴하도록 하는 몇가지의 시나리오가 있습니다.시스템은 화면 전면(foreground)에 있는 액티비티가 더 많은 리소스들을 요구하면 메모리를 복구하기 위해 오랫동안 사용되지 않고 있는 백그라운드(background) 프로세스(process)를 셧다운(shut down)해야만 하므로 여러분의 액티비티를 파괴할 지도 모릅니다. 


 사용자가 Back 버튼을 누르거나 액티비티 스스로 finish 를 해서 여러분의 액티비티를 파괴(destroy)했다는 것은 액티비티는 더이상 필요로 하지 않다는 것을 표시하는 행위이므로 액티비티 인스턴스는 영원히 사라진 다는 개념입니다. 어쨋든, 시스템이 시스템 제약으로 인하여 액티비티를 파괴할 때(보통의 앱 동작을 안하고), 심지어 실제로 액티비티 인스턴스(instance)가 파괴되더라도 시스템은 액티비티가 존재했었다는 것을 기억합니다. 그래서 시스템은 액티비티가 파괴될 때 액티비티의 상태가 기록되어 있는 저장된 데이터 세트(set)를 사용하여 새로운 액티비티 인스턴스를 생성합니다. 이전 상태를 복구하는데 사용하는 저장된 데이터(data)는 "instance state" 라고 불려지며 key-value 쌍으로 저장된 Bundle 객체의 컬렉션(collection)입니다.


Caution : 여러분의 액티비티는 사용자가 화면을 회전할 때 마다 파괴되고(destroyed) 다시 생성(recreated) 됩니다. 화면의 방향이 바뀌어질때, 시스템이 전면(foreground)에 있는 액티비티를 파괴하고(destroyed) 다시 생성(recreated) 하는 이유는 화면의 설정값들이 바뀔 수도 있고 액티비티가 대체 자원(alternative resources)을 필요로 할 수 도 있기 때문입니다.(마치 레이아웃layout 처럼)


 기본적으로, 시스템은 액티비티 레이아웃안에 있는 각 뷰(View) 객체에 대한 정보( EditText 객체 안에 작성되어 있는 텍스트와 같은)를 저장하기 위해 Bundle 인스턴스를 사용합니다. 그래서 만약 여러분의 액티비티 인스턴스가 파괴되고 다시 생성된다면, 레이아웃의 상태는 여러분이 별도의 코드를 작성하지 않고도 복구되어집니다. 어쨋든, 여러분의 액티비티는 사용자의 액티비티 진행상황을 저장하고 있는 멤버변수와 같이 더 많은 상태정보를 가져야 할 수도 있습니다.


  Note : Android 시스템이 액티비티안에 있는 뷰의 상태를 복구하기 위해서는 반드시 각 View 들이 android:id 속성에 적용된 유니크한 ID 를 가지고 있어야만 합니다.


 ​액티비티 상태에 대한 추가적인 데이터를 저장하기 위해서, 여러분은 onSaveInstanceState() 콜백(callback) 메소드를 오버라이드(override) 해야만 합니다. 시스템은 사용자가 액티비티를 떠날 때 이 메소들을 호출하며, 액티비티가 의도하지 않게 파괴(destroyed)되어 질때, 저장되어 질 Bundle 객체를 매개변수로 전달합니다. 만약 시스템이 나중에 액티비티 인스턴스(instance)를 다시 생성해야 한다면, onRestoreInstanceState()와  onCreate() 메소드, 둘 모두에게 같은 Bundle 객체를 전달합니다.




그림 2. 시스템이 여러분의 액티비티를 stop 하기 시작하면서, onSaveInstanceState()를 호출합니다.(1) 그래서 여러분은 액티비티를 다시 생성(recreate) 해야하는 경우에 저장하고 싶은 상태 데이터를 추가적으로 지정할 수 있습니다. 만약 액티비티가 파괴되고 같은 인스턴스가 다시 생성되어야 한다면, 시스템은 onCreate() 메소드(1) 와 onRestoreInstanceState() 메소드(3), 둘 모두에 (1)과정에서 정의된 상태 데이터를 전달합니다. 




액티비티 상태 저장하기(Save Your Activity State)

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

 여러분의 액티비티가 stop 되기 시작하면서, 시스템은 onSaveInstanceState()를 호출합니다. 그래서 여러분의 액티비티(Activity)는 key-value 쌍의 컬렉션(collection)으로 상태 정보를 저장할 수 있습니다. 기본적으로 이 메소드는 EditText의 Text 나 ListView의 스크롤 위치(scroll position) 같은 액티비티 뷰 계층 상태를 저장하도록 구현되어 있습니다. 


 액티비티에 대한 추가적인 상태 정보를 저장하기 위해서는 반드시 onSaveInstanceState()를 구현해야만 합니다. 그리고 key-value쌍의 Bundle 객체를 추가해야만 합니다. 예를 들어:


static final String STATE_SCORE = "playerScore";

static final String STATE_LEVEL = "playerLevel";

...


@Override

public void onSaveInstanceState(Bundle savedInstanceState) {

    // Save the user's current game state

    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);

    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);

    

    // Always call the superclass so it can save the view hierarchy state

    super.onSaveInstanceState(savedInstanceState);

}


Caution : 기본 구현으로 뷰 계층의 상태를 저장할 수 있도록 onSaveInstanceState() 메소드의 슈퍼클래스(superclass)는 항상 호출해야 합니다.


  


액티비티 상태 복구하기(Restore Your Activity State)

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

 이전에 destroyed된 액티비티가 다시 생성(recreate)되어 질 때, 여러분은 시스템이 전달한 Bundle 객체로 부터 저장된 상태를 회복할 수 있습니다. onCreate()와 onRestoreInstance() 콜백(callback) 메소드,  둘 모두 인스턴스들(instances)의 상태 정보를 가지고 있는 같은 Bundle 객체를 받게 됩니다.


 onCreate() 메소드는 액티비티가 처음 만들어지든 이전에 파괴된 것이 다시 만들어지든 상관없이 호출되어 지기 때문에, 여러분은 반드시 데이터를 읽기 전에 먼저 Bundle 객체가 null 인지 아닌지 체크해야만 합니다. 만약 null 이면, 시스템은 파과되기 이전상태를 복구하는 대신에 새로운 액티비티의 인스턴스를 생성합니다.



onCreate()안에서 몇가지 상태 데이터를 저장하는 방법에 대한 예입니다.

 @Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState); // Always call the superclass first

   

    // Check whether we're recreating a previously destroyed instance

    if (savedInstanceState != null) {

        // Restore value of members from saved state

        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);

        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);

    } else {

        // Probably initialize members with default values for a new instance

    }

    ...

}



onCreate() 메소드에서 상태를 복구하는 대신에 onStart() 메소드 다음에 호출되는 onRestoreInstanceState()를 선택할 수도 있습니다. 시스템은 복구하기위한 상태가 저장되어 있을 때만 이 메소드를 호출하기 때문에 여러분은 Bundle 객체가 null 인지 아닌지 체크할 필요가 없습니다.


 public void onRestoreInstanceState(Bundle savedInstanceState) {

    // Always call the superclass so it can restore the view hierarchy

    super.onRestoreInstanceState(savedInstanceState);

   

    // Restore state members from saved instance

    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);

    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);

}

Caution : 기본적으로 뷰 계층의 상태를 복구할 수 있도록 구현된 onRestoreInstatanceState()의 슈퍼클래스의 메소드는 항상 호출해야만 합니다.


 실행 중에 다시 시작하라는 이벤트(화면이 회전할 때와 같이)로 인해 액티비티가 다시 생성되야 할 때에 대한 자세한 내용을 알고싶다면 개발자 사이트의 Handling Runtime Changes 를 읽어보시기 바랍니다. 

반응형
반응형

 액티비티(Activity)의 올바른 정지하기(stopping)와 재시작하기(restarting)는 사용자가 앱이 항상 살아있고 그들의 프로세스(process)를 잃지 않는 다고 인식하는 것을 보장하는데 있어서 가장 중요한 라이프사이클(lifecycle) 과정입니다.

 

여러분의 액티비티가 중지(stopped)되고 재시작(restarted)되는 몇가지 주요한 시나리오들(scenarios)이 있습니다: 


° 사용자가 최근 사용앱 목록(Recent Apps windows)를 열고 여러분의 앱으로 부터 다른 앱으로 전환합니다. 현재 화면 전면(foreground)에 있는 여러분 앱의 액티비티는 정지(stopped) 됩니다. 만약 사용자가 홈 화면(Home screen) 런처 아이콘(launcher icon) 이나 최근 사용앱 목록(Recent Apps windows)을 통해 여러분의 앱으로 되돌아오면, 액티비티는 재 시작(restart) 됩니다.


° 사용자가 여러분의 앱안에서 새로운 액티비티를 시작하는 작업을 수행합니다. 두 번째 액티비티(Second Activity)가 생성될 때, 현재 액티비티는 정지(stopped) 됩니다. 만약 사용자가 Back 버튼을 누르고 나면, 첫 번째(First Activity)가 재 시작(restart) 됩니다.


° 사용자의 휴대전화에서 여러분의 앱을 사용하는 동안 전화를 수신합니다.



 Activity 클래스는 여러분의 액티비티가 정지하고 다시시작할때 할 처리내용들을 작업할 수 있도록 onStop()과 onRestart()라는 2개의 라이프사이클(Lifecycle) 메소드를 제공합니다. 부분적으로 가려진 UI 장애물을 식별하는 paused 상태와 다르게, stopped 상태는 UI 가 더이상 보이지 않고 사용자의 포거스(focus)가 별도의 액티비티(또는 완전히 다른 앱)에 있다는 것을 보증합니다.


Note: stopped 될 때, 액티비티 인스턴스는 시스템 메모리안에 여전히 남아있기 때문에, 가능한 여러분은 onStop()과 onRestart()(onStart()도 역시)를 구현할 필요는 없습니다. 간단한 연산을 하는 대부분의 액티비티들은, onPause()를 사용해서 시스템 리소스들로부터 연결을 끊고 진행중인 동작들을 일시정지 하도록 하기에 액티비티의 stop과 restart는 잘 될 것입니다.




 

그림 1. 사용자가 액티비티를 떠날 때, 시스템은 액티비티를 멈추기 위해 onStop() 을 호출합니다.(1) 만약 사용자가 stopped 되어 있는 액티비티로 다시 돌아온다면 시스템은 onRestart()를 호출합니다.(2) 다음으로 빠르게 onStart()(3) 와 onResume()(4) 을 호출합니다. 시스템은 항상 onStop() 을 호출하기 전에 onPause()를 호출하기 때문에 무슨일이 있어도 액티비티가 정지되는 시나리오(scenario)는 발생하지 않습니다.




액티비티 정지(Stop your Activity)

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

 액티비티가 onStop() 메소드를 호출받았을 때, 그 것은 더이상 보이지 않기에 사용자가 사용하지 않는 동안 필요하지 않은 대부분의 리소스들은 릴리즈(release) 해야 합니다. 여러분의 액티비티가 stopped 되어 있을때, 시스템은 시스템 메모리의 복구가 필요할 때 액티비티 인스턴스를 파괴(destroy)할 지도 모릅니다. 극단적인 경우, 시스템은 여러분의 앱 프로세스(process)를 액티비티의 마지막 onDestroy() 콜백(callback) 호출 없이 죽여(kill) 버릴지도 모릅니다. 그래서 여러분은 메모리 누수(memory leak)를 일으키는 리소스들을 onStop() 을 사용하여 릴리지(release)해야 하는 것이 중요합니다.


 비록 onPause() 메소드가 onSop() 메소드 전에 호출되더라도, 여러분은 onStop()을 사용하여 데이터베이스(database)의 저장(writing) 같은 CPU을 강하게 사용하는 큰 작업을 처리해야만 합니다.


예를 들어, 여기 영구적인 저장소에 노트 원고(draft note)의 내용물을 저장하는 onStop() 의 구현이 있습니다.

 @Override

protected void onStop() {

    super.onStop();  // Always call the superclass method first


    // Save the note's current draft, because the activity is stopping

    // and we want to be sure the current note progress isn't lost.

    ContentValues values = new ContentValues();

    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());

    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());


    getContentResolver().update(

            mUri,    // The URI for the note to update.

            values,  // The map of column names and new values to apply to them.

            null,    // No SELECT criteria are used.

            null     // No WHERE columns are used.

            );

}


 여러분의 액티비티가 stopped 일때, Activity 객체는 메모리안에 여전히 거주하고 있고 액티비티가 resume 될때 다시 호출됩니다. 여러분은 Resume 상태로 읽어 올라가면서 호출되는 어떠한 콜백(callback)이 진행되는 동안에도 생성되어 있는 컴포넌트들(components) 을 다시 초기화할 필요는 없습니니다. 시스템은 또한 레이아웃(layout)안에 있는 각 각의 View에 대한 현재 상태와 진행사항을 유지하고 있습니다.그렇기에 사용자가 EditText 위젯(widget)안에 작성했던 텍스트(Text) 내용물(contents)은 여러분이 별도의 저장이나 읽기를 할 필요없이 메모리에 남아있습니다. 


Note : 심지어 시스템이 액티비티가 stopped 된 상태에서 파괴(destroy)하더라도, ViewEditText안에 있는 text ) 의 객체 상태는Bundle(key-value 쌍의 덩어리(blob))안에 여전히 남아있으며, 사용자가 같은 액티비티의 인스턴스로 되돌아 온다면 그 것들을 다시 읽어들입니다.( 다음 시간에 액티비티가 파괴(destroy)되고 다시 생성(recreate)할 경우 Bundle 을 사용하여 다른 상태 데이터(data)를 저장하는 것에 대해 알아보겠습니다.)





액티비티의 시작/재시작 ( Start / Restart Your Activity)

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

 여러분의 액티비티가 stopped 상태에서 화면 전면(foreground)로 돌아 올 때, onRestart()의 호출을 받게 됩니다. 시스템은 또한 액티비비티가 화면에 보이기 시작하는(처음 만들어지든 다시 시작하든) 매 순간마다 발생하는 onStart() 메소드도 호출합니다. 어쨋든, onRestart()메소드는 오직 액티비티가 stopped 상태에서 resume 될 때만 호출되어 집니다. 그래서 파괴(destroy) 되지 않은 액티비티가 stopped 되기 이전의 상황으로 필요하다면 다시 읽어들이는 작업을 수행할 수 있습니다.


 액티비티의 상태를 읽어들이기 위해 onRestart()를 사용하는 것은 매우 드문 일입니다. 그래서 일반적인 앱들에게 이 메소드를 적용하는 것에 대해서는 어떠한 가이드라인(guideline)도 없습니다. 어쨋든 여러분의 onStop() 메소드는 근본적으로 모든 액티비티의 리소스들을 깔끔하게 제거하도록 되어 있기 때문에, 여러분의 액티비티가 다시 시작할 때 그 것들을 다시 인스터스화 할 필요가 있습니다. 아직 여러분은 액티비티를 처음 생성할 때(액티비티의 인스턴스가 존재하지 않을 때) 그 것들을 인스턴스화 할 필요가 있습니다. 시스템은 여러분의 액티비티가 처음 만들어 질때와 stopped 상태에서 다시 시작할 때의 둘 모두에서 onStart()를 호출하기 때문에 이번시간에 여러분은 onStop() 메소드의 대응 상황으로 onStart() 콜백(callback) 메소드를 사용하도록 합니다.


 예를 들어, 사용자가 오랫동안 떠나 있다가 액티비티로 다시 돌아올 수도 있기 때문에, onStart() 메소드는 시스템 기능들이 사용되는지 확인하는 좋은 위치가 됩니다.

 @Override

protected void onStart() {

    super.onStart();  // Always call the superclass method first

    

    // The activity is either being restarted or started for the first time

    // so this is where we should make sure that GPS is enabled

    LocationManager locationManager = 

            (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

    

    if (!gpsEnabled) {

        // Create a dialog here that requests the user to enable GPS, and use an intent

        // with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action

        // to take the user to the Settings screen to enable GPS when they click "OK"

    }

}


@Override

protected void onRestart() {

    super.onRestart();  // Always call the superclass method first

    

    // Activity being restarted from stopped state    

}


 시스템은 여러분의 액티비티를 파괴(destroy)할 때, 액티비티의 onDestroy() 메소드를 호출합니다. 일반적으로 여러분은 onStop()에서 대부분의 리소스들을 릴리즈(release) 하기 때문에 onDestroy() 호출을 받을 때, 대부분의 앱이 해야할 일이 더 이상 없습니니다. 이 메소드는 려어분이 메모리 누수(memory leak)를 일으키는 리소스들에 대해 제거할 수 있는 마지막 기회입니다. 그렇기에 여러분은 추가적으로 스레드들(Threads)이 파괴되었는지 다른 장기 실행 작업이 중지되어 있는지 확인해야 합니다.

반응형
반응형

 보통 앱을 사용하는 동안, 전면(foreground)의 액티비티는 때때로 pause의 이유가 되는 다른 보여지는 컴포넌트들(components)에 의해 가려지게 됩니다. 예를 들어, 반투명한 액티비티가 열릴 때( 다이얼로그 (Dialog) 스타일 중 하나 처럼), 이전 액티비티는 일시정지(pause) 됩니다. 현재 액티비티는 포커스에 없지만 여전히 부분적으로 보여지며 일시정지된(paused) 상태로 남아있습니다.


 어쨋든, 액티비티는 완전히 가려졌고 보이지 않을 때, stop 이 됩니다.(다음 시간에 살펴보겠습니다.)


 여러분의 액티비티가 paused 상태로 들어감으로서, 시스템은 액티비티에 있는 onPause() 메소드를 호출합니다. 이 곳에 paused 되어 있는 동안 지속되면 안되는 동작들을 멈추거나(video와 같은) 사용자가 여러분의 앱을 떠날 때 영구적으로 저장해야만 하는 어떤 정보들을 저장하도록 해야 합니다. 만약 사용자가 여러분의 액티비티에 되돌아 왔다면, 시스템은 onResume() 메소드를 호출하고 이어하기(resume)를 합니다.


 Note: 여러분의 액티비티가 onPause() 호출을 받았을 때, 액티비티는 잠시동안 일시정지(pause)되고 사용자가 여러분의 액티비티에서 포커스를 반환 할 수 있다는 표시일 수 있습니다. 어쨋든, 일반적으로 onPause()는 사용자가 여러분의 앱을 떠나는 것을 처음 표시됩니다.


 

 

그림 1. 여러분의 액티비티를 반투명 액티비티가 가렸을 때, 시스템은 onPause()를 호출하고 액티비티는 Paused 상태에서 잠시 기다리게 됩니다.(1) , 만약 사용자가 paused 상태에서 액티비티로 돌아오면, 시스템은 onResume() 을 호출합니다.(2)




액티비티 일시정지(Pause Your Activity)

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

 시스템이 여러분의 액티비티에 대해 onPause() 를 호출할 때, 기술적으로는 여러분의 액티비티가 부분적으로나마 보인다는 것을 의미합니다. 하지만, 대부분의 경우 사용자가 액티비티를 떠났고 곧 이어 Stopped 상태로 들어간다는 것을 나타냅니다. 여러분은 일반적으로onPause() 콜백(callback)안에서 아래 내용을 사용하셔야 합니다.


° 애니메이션들(animations)이나 CPU 를 소모해야만 하는 동작들을 정지하기

° 사용자가 액티비티를 떠날 때 영구적으로 저장되기를 기대하는( 이메일 원고(a draft email)와 같은) 저장되지 않은 변경사항들을 커밋(commit)하기

° 브로드캐스트 리시버(broadcast receivers), 센서(GPS 처럼) 제어들, 사용자가 필요하지 않고 액티비티가 일시정지되어 있는 동안 베터리 소모에 영향을 미치는 어떤 리소스들(resources) 처럼 시스템 리소스들 없애기



예를 들어, 만약 여러분의 어플이 Camera를 사용한다면, onPause() 메소드는 이것을 없애기에 좋은 위치입니다.

 @Override

public void onPause() {

    super.onPause();  // Always call the superclass method first


    // Release the Camera because we don't need it when paused

    // and other activities might need to use it.

    if (mCamera != null) {

       mCamera.release()

      mCamera = null;

    }

}


 일반적으로, 여러분은 onPause()에서 영구적인 저장장치에 사용자의 변경사항( 하나의 form안에 들어간 개인 정보같은 )을 저장하지 않도록 합니다. 여러분은 오직 사용자가 변경사항들을 틀림없이 자동으로 저장되어지기를 기대할 때( email의 원고(draft)를 작성할때와 같이),onPause()안에 사용자의 변경사항을 저장하도록 하셔야 합니다. 어쨋든, 여러분은 onPause() 동안 데이터베이스(database) 쓰기와 같은CPU를 강하게 사용하는 작업은 회피해야만 합니다. 왜냐하면, 다음 액티비티로 보여지는 것이 전환되는 것을 느리게 할 수 있기 때문입니다.( 여러분은 onStop() 하는 동안 무거운 로딩(loadshutdown 명령들을 수행하도록 대체하셔야 합니다.)


 여러분은 사용자가 액티비티를 떠나기 시작한다면 빠르게 사용자의 다음 목적지로 전환되도록 하기 위해 onPause() 메소드 안에 비교적 간단한 연산의 양을 유지하셔야 합니다.


 Note: 여러분의 앱이 pause 될때, 액티비티 인스턴스는 메모리안에 거주하며 액티비티가 resume 될 때 다시 호출됩니다. 여러분은Resumed 상태로 올라오면서 읽어지는 어떤 콜백(callback) 메소드들에도 컴포넌트들(components)을 다시 초기화 시킬 필요가 없습니다.




액티비티 이어하기(Resume Your Activity)

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

 Paused 상태에서 사용자가 여러분의 액티비티를 이어할 때(resume), 시스템은 onResume() 메소드를 호출합니다.


 액티비티가 가장 처음 만들어질 때를 포함하여, 여러분의 액티비티가 화면의 전면(foreground)에 나타날때, 시스템은 onResume()메소를 호출한다는 것을 알아야 합니다. 여러분은 onPause() 동안 없앴던 컴포넌트들(components) 과 매번 액티비티가 Resumed 상태가 될 때마다 수행해야만 하는 작업들( 애니메이션들(animations) 시작과 오직 사용자 포커스를 가진 액티비티에서만 사용되는 컴포넌트들(components) 초기화 같은)을 초기화 하도록 onResume()을 구현해야 합니다.


 아래의 onResume() 예제는 위의 onPause() 예제에 대응 되어 있습니다. 그래서 액티비티가 pause 될 때 없앴던 카메라(camera)를 초기화 하고 있습니다.


 @Override

public void onResume() {

    super.onResume();  // Always call the superclass method first


    // Get the Camera instance as the activity achieves full user focus

    if (mCamera == null) {

        initializeCamera(); // Local method to handle camera init

    }

}


반응형
반응형

 앱의 런처(Launcher) 액티비티(Activity) 지정하기

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

 디바이스의 홈 화면(Home Screen)에서 여러분의 앱 아이콘을 선택했을때, 시스템은 여러분의 앱에서 "launcher"(또는 "main")로 선언된 액티비티의 onCreate() 메소드를 호출합니다. 이 액티비티는 여러분 앱의 사용자 인터페이스(user interface : UI)에 진입하는 메인(main)으로 제공된 액티비티입니다. 


 여러분 프로젝트 디렉토리의 최상위에 있는 AndroidManifest.xml 메니페이스 파일안에 메인(main) 액티비티로 사용하도록 선언 할 수 있습니다.


 메인(main) 액티비티는 여러분 앱의 메니페스트 파일안에 반드시 Main action(액션)과  Launcher category(카테고리)를 포함한 <intent-filter> 태그를 가지고 선언되어 있어야 합니다.


예:

 <activity android:name=".MainActivity" android:label="@string/app_name">

    <intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

    </intent-filter>

</activity>

 


Note : 여러분이 Android SDK Tools 를 사용하여 새로운 액티비티 프로젝트를 생성했을때, Activity 클래스 하나가 기본 프로젝트 파일로 포함되어 있으며 이 Activity 는 filter 를 가지고 메니페스트안에 선언되어 있습니다.


 만약 여러분의 액티비티들 중 하나에 MAIN action 이나 LAUNCHER category 중 하나라도 선언하지 않으면, 여러분의 앱 아이콘(App Icon)은 홈 화면(Home Screen)의 앱(App) 목록에 나타나지 않을 것입니다.




 인스턴스 생성하기(Create New Instance)

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

 대부분의 앱은 사용자가 서로 다른 동작들을 하도록 하는 여러개의 다른 액티비티들을 포함하고 있습니다. 사용자가 여러분의 앱 아이콘을 클릭하여 처음 만들어진 메인 액티비티든지 사용자의 액션에 응답하여 시작하는 다른 액티비티 든지, 시스템은 onCreate() 메소드를 호출함으로서 새로운 Activity 인스턴스(instance)를 만들어 냅니다. 


 액티비티(Activity)의 전체 생애(Life)동안 오직 한번만 일어나는 기본 앱의 시작 로직(Startup Logic)을 실행시키기 위해 여러분은 반드시onCreate() 메소드를 구현해야만 합니다. 예를 들어, 여러분의 onCreate() 구현은 사용자 인터페이스(user interface: UI)를 정의해야 하고 몇가지 클래스 범위의 변수를 인스턴스화(instantiate) 하도록 합니다.


 예를 들어, 아래 나오는 onCreate() 메소드의 예제는 사용자 인터페이스(user interface:UI)-(XML 레이아웃 파일에 정의된), 멤버변수들의 정의, 그리고 UI의 몇가지 환경설정 같은 액티비티에 대한 몇몇 기본 설정(setup)을 실시하도록 하는 몇가지 코드를 보여줍니다.


 TextView mTextView; // Member variable for text view in the layout


@Override

public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);


    // Set the user interface layout for this Activity

    // The layout file is defined in the project res/layout/main_activity.xml file

    setContentView(R.layout.main_activity);

    

    // Initialize member TextView so we can manipulate it later

    mTextView = (TextView) findViewById(R.id.text_message);

    

    // Make sure we're running on Honeycomb or higher to use ActionBar APIs

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

        // For the main activity, make sure the app icon in the action bar

        // does not behave as a button

        ActionBar actionBar = getActionBar();

        actionBar.setHomeButtonEnabled(false);

    }

}

Caution : SDK_INT의 사용은 Android 2.0(API level 5) 이상의 예전 시스템에서 새로운 APIs를 사용하는 것을 제한합니다. 예전 버전에서는 실행중 예외상황을 보게 될 겁니다. 



 onCreate()의 실행이 끝날을때, 시스템은 onStart()와 onResume()을 빠르고 성공적으로 호출합니다. 여러분의 액티비티는 절대로Created 와 Started 상태에서 머무르지 않습니다. 기술적으로 액티비티는 onStart()를 호출했을 때 사용자에게 보여지도록 되어있습니다. 하지만, onResume() 이 빠르게 따라오고 , 전화를 수신하거나, 사용자가 다른 액티비티로 이동하거나, 또는 디바이스 화면이 꺼질 때와 같이 액티비티가 전환되기 위해 어떤 일이 일어날때 까지는 Resumed 상태에서 남아있게 됩니다.


 이어지는 다른 수업에서, 여러분은 onStart()와 onResume() 같은 시작 설정 메소드들(start up methods)을 Paused 나 Stopped 상태로 부터 다시 이어하도록 하기 위해 액티비티의 생애주기(Lifecycle) 동안 어떻게 유용하게 사용할 지에 대해 보게 될 것입니다.


Note : onCreate() 메소드는 나중에 (액티비티 다시 생성하기)Recreating an Activity 수업에서 검토할 savedInstanceState 라고 불려지는 하나의 파라미터(parameter)를 포함하고 있습니다.



그림 2. 새로운 액티비티 인스턴스(Activity instance)가 생성될 때, 시스템이 순서대로 호출하는 3개의 주요 콜백(callback)들에 중점을 둔 액티비티 생명주기(Activity Lifecycle) 구조의 또 다른 그림. 이 콜백(callback)들의 순서가 완료되면, 액티비티는 Resumed 상태에 도착하게 되고 다른 액티비티로 전환할 때 까지 사용자와 상호 작용할 수 있게 됩니다. 




액티비티 파괴하기(Destroy the Activity)

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

 액티비티의 첫번째 생명주기 콜백(callback)은 onCreate()이며, 이 콜백들(callbacks)의 가장 마지막은 onDestroy() 입니다. 시스템은 액티비티 인스턴스가 시스템 메모리로부터 완전히 제거되기 시작할 때 마지막 신호로서 액티비티에서 이 메소드를 호출합니다.


 대부분의 어플들은 이 메소드의 구현이 필요하지 않습니다. 왜냐하면 지역 클래스 참조(references)들은 액티비티와 함께 파괴되어 지고 액티비티는 반드시 onPause() 와 onStop() 동안 대부분의 정리 작업(Cleanup)을 수행하기 때문입니다. 어쨋든, 만약 여러분의 액티비티가 onCreate()에서 만들어진 백그라운드(background스레드(Thread)를 포함하거나 오랫동안 실행되는 또 다른 리소스들로서 완전하게 닫히지 않고 잠재적으로 메모리 누수(memory leak)를 일으킬 수 있다면, 여러분은 onDestroy() 에서 그것들을 가급적 죽여야(kill) 합니다.


 @Override

public void onDestroy() {

    super.onDestroy();  // Always call the superclass

    

    // Stop method tracing that the activity started during onCreate()

    android.os.Debug.stopMethodTracing();

}


Note : 시스템은 한가지 경우(여러분이 onCreate() 메소드에서 finish()를 호출했을 때)를 제외한 모든 상황에서 onPause()와 onStop()이 호출된 이후에 onDestroy()를 호출합니다. 여러분의 액티비티가 또 다른 액티비티를 시작(Launch)하기 위한 임시 의사 결정자로 동작할 때와 같은 몇몇 경우에서 여러분은 액티비티를 파과하기 위해 onCreate() 안에 finish()를 호출할 지도 모릅니다. 이 경우 시스템은 다른 생명주기 메소드들(Lifecycle methods)중 어떤 것도 호출하지 않고 onDestroy()를 즉시 호출합니다.  

반응형
반응형

 main() 메소드를 가지고 시작하는 다른 프로그래밍의 페러다임과는 다르게, 안드로이드 시스템은 액티비티의 생명주기(lifecycle)의 특정 상황에 대응하는 특정 콜백메소드(callback method)를 발동함으로서 액티비티 인스턴스(instance)안의 코드를 초기화 합니다. 액티비티가 시작할 때 호출되는 순차적인 콜백 메소드들과 액티비티가 파괴될 때 호출되는 순차적인 콜백 메소드들이 있습니다. 


 이번 시간에는 가장 중요한 라이프사이클(lifecycle) 메소드들의 개요를 제공할 것입니다. 그리고 여러분에게 새로 액티비티의 인스턴스(instance)가 만들어질 때 처음 호출하는 콜백을 제어하는 방법을 보여드리겠습니다.



생명주기(라이프사이클 : Lifecycle) 콜백(callback)들 이해하기

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

 하나의 액티비티가 살아있는 동안, 시스템은 피라미드(Pyramid)의 단계와 흡사한 순서로 생명주기(lifecycle) 메소드들의 주요 세트(Set)를 호출합니다. 그렇다, 액티비티(Activity) 생명주기(Lifecycle)의 각 상태는 피라미드(Pyramid)의 구분된 단계와 같다. 시스템이 새로운 액티비티의 인스턴스(instance)를 만듦으로서, 각 콜백(callback) 메소드는 액티비티를 가장 윗 단계를 향해 한단계 씩 이동시킵니다. 피라미드의 가장 위(Top)는 액티비티가 화면의 전면(foreground)에서 실행중이고 사용자(user)와 상호작용(interaction)을 할 수 있다는 것을 가리킵니다.


 사용자(user)가 액티비티를 떠나기 시작하면, 시스템은 액티비티를 파괴하기 위해 피라미드(Pyramid)의 아래쪽을 향해 단계를 이동시키는 또 다른 메소드들을 호출합니다. 몇몇의 경우, 액티비티는 피라미드의 아래 일 부분으로 이동하여 기다릴 수 도 있고( 다른 앱으로 전환될 때와 같이), 이 지점에서 다시 피라미드의 상단(Top)을 향해 단계를 이동해서(만약 사용자가 다시 액티비티로 돌아온다면) 사용자가 중단 된 지점부터 다시 시작할 수 도 있습니다.




그림 1. 피라미드(Pyramid)의 단계로 표현된, 액티비티 생명주기(Activity Lifecycle)에 대한 간략한 그림. 이 그림은 가장 위에있는Resumed 을 향한 단계에서 액티비티가 가진 모든 콜백(callback)들과 아래로 향하는 단계에서의 콜백들(callback)의 사용 방법을 보여줍니다. 액티비티는 Paused 와 Stopped 상황에서도 역시 Resumed 로 돌아갈 수 있습니다.



 여러분 액티비티의 복잡도에 따라, 여러분은 모든 생명주기(Lifecycle) 메소들들을 구현할 필요는 없습니다.

어쨋든, 사용자가 기대한 대로 여러분의 앱이 동작하는 것을 보장하기 위해서는 이 메소드들을 이해하는 것이 매우 중요합니다. 여러분의 액티비티 생명주기(Lifecycle) 메소드들을 구현하는 것은 다양한 방법으로 동작되는 여러분의 앱이 적절하게 동작되는 것을 보장합니다. 

 이런 것들을 포함합니다.:


° 앱을 사용하는 동안 사용자가 전화를 수신하거나 다른 앱으로 전환하는 경우 충돌 하지 않습니다.

° 사용자가 액티비티를 사용하지 않을 때 시스템 자원들의 값을 없애지 않습니다.

° 사용자가 앱을 떠났다가 나중에 다시 돌아왔을때, 사용자의 진행순서를 잃어버리지 않습니다.

° 화면의 방향이 가로(landscape)와 세로(portrait) 사이에서 회전할 때 사용자의 진행 상황을 잃어버리거나 충돌하지 않습니다.  



 수업을 따라하다 보면, 그림 1의 그림과 같이 서로 다른 상태 사이에서 액티비티의 상태를 전환하는 여러가지 상황이 있다는 것을 배우게 될 것입니다. 어쨋든, 이러한 상태들 중 3개는 고정될 수 있습니다. 즉, 액티비티는 이 3가지 상태중 하나에서 장시간 동안 존재할 수 있습니다.



 Resumed

 이 상태에서, 액티비티는 화면의 전면(foreground)에 있고 사용자(user)와 상호작용(interaction)을 할 수 있습니다.( 때로는 "실행중(running)"상태라고도 합니다.) 


 Paused

 이 상태에서, 액티비티는 다른 액티비티( 반 투명하거나 화면전체를 사용하지 않는 액티비티)에 의해 부분적으로 가려져 있습니다. 일시정지(Paused)된 액티비티는 사용자 입력을 받을 수 없으며 어떤 코드도 실행 할 수 없습니다.


 Stopped

 이 상태에서, 액티비티는 완전하게 숨겨져서 사용자에게 보이지 않습니다.( 이 상태는 백그라운드(background)에 있는 것으로 간주됩니다.) 정지(Stopped)되어 있는 동안, 액티비티 인스턴스(instance)와 멤버변수(variable)과 같은 모든 상태정보들은 남아있습니다. 하지만 역시 어떤 코드도 실행 할 수 없습니다.



다른 상태들은(Created 와 Started) 일시적으로 존재하며 시스템이 다음 생명주기(Lifecycle) 콜백(callback)메소드를 호출함으로서 빠르게 다음 단계로 전환합니다. 즉, 시스템은 onCreate()를 호출한 후, 빠르게 onStart(), 또 빠르게 onResumed()에 도착하도록 합니다. 




 이것이 기본적인 액티비티 생명주기(Activity Lifecycle) 입니다. 이제 특정 라이프사이클 동작의 몇가지를 학습하도록 하겠습니다.

반응형
반응형

사용자의 네비게이션을 통해, 여러분의 앱은 back을 하고, 아웃된다. 이 순간 액티비티 인스턴스는 그들의 생명주기(lifecycle)안에서 서로 다른 상태로 전환됩니다. 액티비키가 처음 시작할 때 만들어진 인스턴스를 시스템의 전면(foreground)으로 오도록 하고 사용자의 포커스를 받아옵니다. 이 과정이 진행되는 동안, 안드로이드 시스템은 여러분이 사용자 인터페이스(UI)와 다른 구성물들을 생성한 액티비티에 있는 하나의 연속된 생명주기(lifecycle) 메소드들을 호출합니다. 만약 사용자가 다른 액티비티를 실행하거나 다른 앱으로 전환하는 행동을 한다면 시스템은 액티비티를 백그라운드(background : 액티비티가 더 이상 보이지 않지만 인스턴스(instance)는 온전히 남아있는 상태)로 이동하면서 액티비티에 있는 또 다른 생명주기(lifecycle) 메소드 세트를 호출합니다.


 사용자가 액티비티를 떠나거나(끌때) 다시 돌아올 때 여러분의 액티비티가 하고자 하는 행동을 생명주기(lifecycle) 콜백 메소스(callback method) 안에, 선언할 수 있습니다. 예를 들어보면, 만약 여러분이 스트리밍(streaming)을 받아오는 비디오 플레이어(video player)를 만든다면, 사용자가 또 다른 앱으로 전활 할 때 비디오를 일시정지(pause)하거나 네트워크(network)의 연결을 종료해야 할 지도 모릅니다. 사용자가 다시 돌아올 때, 여러분은 네트워크에 다시 접속을 하고 사용자가 멈췄던 지점(spot)에서 비디오가 다시 재생(resume)할 수 있도록 할 수 있습니다.


 이번 시간에는 각 액티비티 인스턴스(instance)의 중요한 생명주기 콜백 메소드(lifecycle callback method)를 설명하도록 하겠습니다. 그리고 콜백 메소드를 전달받고 사용하는 방법을 소개합니다. 그래서 여러분의 액티비티가 사용자가 원하는 작업을 하게 되며, 더 이상 액티비티가 필요하지 않을 때 시스템 자원을 소비하지 않도록 합니다.




Lessons

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

Activity 시작하기(Starting)

 여러분의 앱을 실핼할 수 있는 방법과 기본 액티비티 생성 방법에 대해 액티비티 생명주기(lifecycle)의 기본사항을 학습합니다.


Activity 일시정지(Pausing) 와 이어하기(Resuming)

 여러분의 액티비티가 일시정지 하거나 이어할 때 발생하는 일과 여러분이 상태의 전환 동안 해야하는 일에 대해 학습합니다.


Activity 정지(Stopping)과 다시 시작하기(Restarting)

 여러분의 액티비티가 완전하게 화면을 벗어나가나 다시 돌아왔을 때 발생하는 일에 대해 학습합니다.


Activity 다시 생성하기(Recreating)

 여러분의 액티비티가 파괴될 때 발생하는 일과 필요할 때 액티비티 상태를 다시 생성할 수 있는 방법에 대해 학습합니다.

반응형
반응형

안드로이드의 최신 버전은 종종 앱에 대한 좋은 API 들을 제공하는 하지만, 여러분은 더 많은 디바이스들이 업데이트를 할 때 까지 예전 버전에 대한 지원을 계속해야 만 합니다. 이번 시간에는 오래된 버전에서 최신 API들의 이득을 얻을 수 있는 방법을 소개하겠습니다. 


 안드로이드 개발자 사이트에는  Google Play Store에 방문한 디바이스의 수를 기반으로 설치되어 있는 Platform Versions 에 대한dashboard 를 정기적으로 업데이트 해주고 있습니다. 일반적으로, 최선버전을 타겟으로 하는 여러분의 앱이 전체 활동하는 디바이스의 90%를 지원하도록 하는 것이 좋은 습관입니다.


 Tip: 여러 안드로이드 버전을 통틀어 가장 좋은 특징과 기능들 제공하기 위해 여러분의 앱에 오래된 버전에서 다양한 최신 플랫폼 API들을 사용하도록 허용하는 Android Support Library 를 사용 해야만 합니다. 



최소(Minimum)와 타겟(Target) API Levels 지정하기

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

 AndroidManifest.xml 파일은 여러분에 앱에 대한 세부사항들이 묘사되어 있습니다. 그리고 이것이 지원하는 Android 버전에 대해서도 식별되어 있습니다. 특히, 여러분의 앱 설계와 테스트에 대응되는 가장 높은 API level과 이에 호환되는 가장 낮은 버전의 API level 을 식별하기 위한 <uses-sdk 요소에 있는 minSdkVersion 과 targetSdkVersion 속성.


 예:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >

    <uses-sdk android:minSdkVersion="4"

                 android:targetSdkVersion="15" />

    ...

</manifest>


 새로운 Android 버전이 출시되면, 몇몇 스타일(Style)과 행동(Behavior)이 바뀔 수 도 있습니다. 여러분의 앱이 이러한 변경 사항을 활용하여 앱의 스타일에 맞는지 확인하도록 하려면, 여러분은 반드시 targetSdkVersion의 값이 최신 안드로이드 버전과 일치하도록 설정해야 만 합니다.


 

 실행할 때 시스템 버전 확인하기

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

 안드로이드는 Build 상수 클래스안에 각 플랫폼 버전에 대한 유일한 코드를 제공하고 있습니다. 가장 높은 API level를 시스템이 사용할 수 있는 경우에만 이 API들의 사용을 보증하기 때문에 이런 상태를 확인하기 위해 여러분의 앱안에 이 코드들을 사용합니다.

 private void setUpActionBar() {

    // Make sure we're running on Honeycomb or higher to use ActionBar APIs

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

        ActionBar actionBar = getActionBar();

        actionBar.setDisplayHomeAsUpEnabled(true);

    }

}


Note : XML 리소스들을 파싱(parsing)할 때, 안드로이드는 현재 디바이스에서 지원하지 않는 XML속성은 무시합니다. 그래서 여러분은 최신버전에서 지원하고 있는 XML 속성에 대해 오래된 버전에서 다운될 걱정없이 안전하게 사용할 수 있습니다. 예를들어, 만약 여러분이 앱에 대해 targetSdkVersion="11"을 설정하면, 기본적으로 안드로이드 3.0버전 이상에서만 포함하고 있는 ActionBar을 포함합니다. 그런다음 액션바에 메뉴 아이템을 추가하기 위해서는, 여러분의 메뉴 리소스 XML안에 android:showAsAction="ifRoom"을 설정할 필요가 있습니다. 안드로이드의 이전 버전은 단순하게 이 showAsAction 속성을 무시하기 때문에(즉, 여러분은 res/menu-v11/로 구분된 별도의 버전이 필요하지 않습니다.), 버전 간 XML파일에서 이 작업을 하는 것은 안전합니다. 



 플랫폼 스타일(Style)과 테마(Theme) 사용하기

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

 안드로이드는 기본 운영체체(OS)의 모양과 느낌을 주는 사용자경험(user experience : UX) 테마(Theme)를 제공합니다. 이 테마들(Themes)은 메니페스트 파일내에서 앱에 적용할 수 있습니다. 스타일(Style)과 테마(Theme)에 내장 된 이것들을 사용함으로서 여러분의 앱은 자연스럽게 새로 릴리즈된 안드로이의 최신 모양과 느낌으로 만들어집니다. 


 

 여러분의 액티비티를 하나의 다이얼로그 박스(Dialog Box)처럼 만들기

 <activity android:theme="@android:style/Theme.Dialog">


 여러분의 액티비티가 투명한 배경을 가지도록 만들기

 <activity android:theme="@android:style/Theme.Translucent">


 res/values/styles.xml 에 정의된 여러분의 커스텀 테마(custom theme) 사용하기

 <activity android:theme="@style/CustomTheme">

 


 여러분의 앱 전체(모든 액티비티들)에 적용하기, <application> 요소의 android:theme 속성을 추가합니다.

 <application android:theme="@style/CustomTheme">



테마(Theme)를 사용하여 만들기에 대한 추가정보는 개발자 사이트의 Styles and Theme 가이드를 참고하시기 바랍니다.  

반응형

+ Recent posts