くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Activity破棄問題をサポートしてくれるIcepickとparceler

破棄されやすいAndroidのActivity/Fragmentたち。ライブラリを使うと簡単に状態を保存/復元できるので、その備忘録。

dependency

repositories {
  maven {url "https://clojars.org/repo/"} // Icepick
}
dependencies {
  // Icepick
  compile 'frankiesardo:icepick:3.2.0'
  provided 'frankiesardo:icepick-processor:3.2.0'
  
  // parceler
  compile 'org.parceler:parceler-api:1.1.9'
  annotationProcessor 'org.parceler:parceler:1.1.9'
}

Icepick

Activity

class ExampleActivity extends Activity {
  @State String username; // 保存するフィールドには、@Stateをつける

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState); // 復元
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState); // 保存
  }
}

Fragment

public class ExampleFragment extends Fragment {
    @State String username;

    @Override
    public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
        super.onViewStateRestored(savedInstanceState);
        Icepick.restoreInstanceState(this, savedInstanceState);  // 復元
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Icepick.saveInstanceState(this, outState);    // 保存
    }
}

Custom View

class CustomView extends View {
  @State int selectedPosition;

  @Override public void onRestoreInstanceState(Parcelable state) {
    super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state)); // 復元
  }
  
  @Override public Parcelable onSaveInstanceState() {
    return Icepick.saveInstanceState(this, super.onSaveInstanceState());  // 保存
  }
}

parceler

対象のクラスに@Parcelをつける

@Parcel
public class Example {
    public String name;

    public Example(String name) {
        this.name = name;
    }
}

保存/復元はこんな感じ

// 保存
Parcelable wrapped = Parcels.wrap(new Example("Andy")); 

// 復元
Example example = Parcels.unwrap(wrapped);
example.getName(); // Andy

parceler + Icepick

IcepickのBundlerを使ってwrap/unwrapする

@Parcel
public class Example {
    public String name;

    public static class Bundler implements icepick.Bundler<Example> {  // icepickのBundlerを個別に定義
        @Override
        public void put(String key, Example example, Bundle bundle) {
            bundle.putParcelable(key, Parcels.wrap(example));
        }

        @Override
        public Example get(String key, Bundle bundle) {
            return Parcels.unwrap(bundle.getParcelable(key));
        }
    }
}

@State()にBundlerを指定する

public class ExampleFragment extends Fragment {

    @State(Example.Bundler.class) Example example; 
}

参考にしたサイト様