Activity 인스턴스 파기 대책에 Icepick을 사용해 본다

2016/02/18에 개최된 DroidKaigi2016의 기조 강연으로 소개된 라이브러리를 시험해 보자! 라는 것으로 꽤 좋았던 「Icepick」을 만져 보았습니다.
이 도서관에서 무엇을 할 수 있는지, 어떤 경우에 사용할 수 있는지 전해지면 다행입니다.

[DroidKaigi2016 1일차 기조강연 슬라이드] OSS 동향을 포착한 실장방침
htps : // speake r에서 ck. 코 m / 와사 베 f / da y1 - y y te-in - d 로이 d 카이 기 - 2016

Icepick이란?



Activity 등의 UI계 객체의 필드의 보존과 복원 부분의 구현을 간단하게 하기 위한 라이브러리입니다. 이것을 사용하면 귀찮은 「Activity 인스턴스 파기 문제」를 스마트하게 해결할 수 있을 것으로 기대할 수 있습니다.

쓰기 시점의 최신 버전은 3.1.0입니다.

여기서 "Activity 인스턴스 파기 문제"는 무엇입니까?



자세한 것은 다른 기사로 쓰려고 생각하고 있습니다만, 얽히 말하면…

· 단말기가 회전하거나 언어 설정을 변경한 경우
· 메모리가 부족한 경우
에 Activity 인스턴스가 삭제됩니다. 그 때 저장하고 싶은 값이 없어지므로 상태가 재설정됩니다.

라는 것입니다. (이 기사 읽고 있는 시점에서 이 문제의 심각성은 알겠다고 생각합니다만…)

사용법



여기에서는 사용법에 대해 설명합니다.

사용하는 샘플 코드는 Github에 업로드하고 있습니다.
htps : // 기주 b. 코 m / Ly 리카 l 마에 st로 / 이세 피 CK mp ぇ

아래 준비(build.gradle 변경)



app 폴더 바로 아래의 build.gradle에 다음 코드를 추가하십시오.

build.gradle
android{

  repositories {
    maven {url "https://clojars.org/repo/"}
  }

  //…略
}

dependencies {
  compile 'frankiesardo:icepick:3.1.1-SNAPSHOT'
  provided 'frankiesardo:icepick-processor:3.1.1-SNAPSHOT'
}

그 1. Activity/Fragment의 필드 인스턴스를 보존·복원한다



먼저 저장하려는 필드에 @State를 붙입니다. 그리고 onSavedInstanceState 메소드내에 Icepick#onSavedInstanceState를, onCreate 메소드내에 Icepick#restoreInstanceState를 실행하도록 합니다.

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private TextView mMsgTextView;

    @State
    String mMessages = "";
    @State
    int mCount = 0;

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

        //略
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Icepick.saveInstanceState(this, outState);
    }
    // 以下略
}

이것뿐입니다. 덧붙여서 IcePick을 사용하지 않으면 다음과 같은 느낌이 듭니다. onCreate내가 특히 엉망이고 key의 치는 실수에 의한 문제도 발생할 것 같네요.

MainActivity.java (Icepick 없음)
public class MainActivity extends AppCompatActivity {

    private TextView mMsgTextView;

    @State
    String mMessages = "";
    @State
    int mCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(savedInstanceState != null){
            mMessages = savedInstanceState.getString("STRING");
            mCount = savedInstanceState.getInt("INTEGER");
        }

        //略
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("STRING", mMessages);
        outState.putInt("INTEGER", mCount);
    }
    // 以下略
}

2. 커스텀 View의 필드 인스턴스 저장 및 복원



커스텀 View의 경우도 그 1과 같이, 저장하고 싶은 필드에 @State 를 붙입니다. 그리고 onSavedInstanceState 메소드내에 Icepick#onSavedInstanceState를, onCreate 메소드내에 Icepick#restoreInstanceState를 실행하도록 합니다.

CustomView.java
public class CustomView extends View {

    @State
    int mColorIndex = 0;

    public CustomView(Context context) {
        super(context);
        init();
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    public Parcelable onSaveInstanceState() {
        return Icepick.saveInstanceState(this, super.onSaveInstanceState());
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state));
        changeColor();
    }

    //以下略
}

3. Activity가 참조하는 TextView와 같은 표준 View의 상태를 유지하는 방법?



그 1에서 했던 것 같은 김으로 참조하는 EditText가 가지는 문자열도 보존·복원의 대상으로 하고 싶을지도 모릅니다만, 현상 할 수 없습니다. 그래서, 이런 일을 하는 경우에는 한 번 String형의 필드에 값을 퇴피시키고 나서 그 필드를 보존·복원 같은 것을 하지 않으면 안됩니다. (이 근처가 조금 귀찮은 곳이지만 ...)

이것은 할 수 없다.
public class MainActivity extends AppCompatActivity {

    @State
    TextView mMsgTextView;

    // 以下略
}

주의점



Icepick은 많은 라이브러리에 의존합니다. (이하는 Icepick 임포트시에 감는 식으로 임포트된 라이브러리들)


메소드 수에 여유가 없는 경우는 주의가 필요할지도 모릅니다. . guava라든지 들어 있는 단계에서 상당한 방법수 있을 것 같지만…

총괄



조금 귀찮은 곳도 있습니다만, 보존해야 할 필드가 많이 있는 경우에는 이것을 사용하면 코드가 깨끗이 하는+버그의 온상이 없어진다, 라고 하기 때문에 혜택을 받을 수 있다고 생각합니다.

좋은 웹페이지 즐겨찾기