Skip to content
Seong-Ug Steve Jung edited this page Apr 21, 2016 · 3 revisions

Agera (스웨덴어로 to act) 안드로이드 어플리케이션의 Activity 와 같은 컴포넌트나 그 내부의 View 나 그와 유사한 Life-Cycle 을 가진 객체들이 데이터를 이용하기 쉽게 돕기 위해 제작된 라이브러리입니다. Functional-Reactive-Programming 의 한 종류로 자연어에 가까운 상태로 When, Where, What 요소들을 깔끔하게 분리시켜주며 단일 표현을 위해 복잡하고 비동기적 처리를 할 수 있습니다.

아래 예제 코드를 통해 Agera 를 특징을 확인하실 수 있습니다. 앞으로 위키를 통해서 javadocagera 의 동작을 설명하도록 하겠습니다.

    public class AgeraActivity extends Activity implements Receiver<Bitmap>, Updatable {
      private static final ExecutorService NETWORK_EXECUTOR = newSingleThreadExecutor();
      private static final ExecutorService DECODE_EXECUTOR = newSingleThreadExecutor();

      private Repository<Result<Bitmap>> background;
      private ImageView backgroundView;

      @Override
      protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Layout 바인딩
        setContentView(R.layout.activity_main);

        // 배경 View 바인딩
        backgroundView = (ImageView) findViewById(R.id.background);

        // 비트맵 요청의 결과를 보관할 저장소(repository) 를 생성합니다.
        // 화면 크기를 기반으로 네트워크를 통해 이미지를 가져오도록 하겠습니다.
        background = repositoryWithInitialValue(Result.<Bitmap>absent())
            .observe() // (옵션사항) 이벤트를 통해 이미지를 갱신합니다. 예제에서는 발생하지 않습니다.
            .onUpdatesPerLoop() // 갱신은 매 Looper 마다 동작합니다. 물론 발생하지 않습니다.
            .getFrom(new Supplier<HttpRequest>() {
              @NonNull
              @Override
              public HttpRequest get() {
                DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                int size = Math.max(displayMetrics.heightPixels, displayMetrics.widthPixels);
                return httpGetRequest(
                    "http://www.gravatar.com/avatar/4df6f4fe5976df17deeea19443d4429d?s=" + size)
                    .compile();
              }
            }) // 화면 크기에 맞춰 HttpRequest 를 생성합니다.
            .goTo(NETWORK_EXECUTOR) // 네트워크 Thread-Executor 로 변경합니다.
            .attemptTransform(httpFunction())
            .orSkip() // http 요청이 실패하면 무시하도록 합니다.
            .goTo(DECODE_EXECUTOR) // Decode Thread-Exector 로 변경합니다.
            .thenTransform(new Function<HttpResponse, Result<Bitmap>>() {
              @NonNull
              @Override
              public Result<Bitmap> apply(@NonNull HttpResponse response) {
                byte[] body = response.getBody();
                return absentIfNull(decodeByteArray(body, 0, body.length));
              }
            }) // 성공한 결과만 Decode 처리하고 실패시 전송하지 않습니다.
            .onDeactivation(SEND_INTERRUPT) // 비동작 선언시 http request 와 decode 를 중단하도록 합니다.
            .compile(); // 최종적으로 저장소(Repository)를 만듭니다.
      }

      @Override
      protected void onResume() {
        super.onResume();
        background.addUpdatable(this); // 저장소로 부터 이벤트를 받도록 등록하고 flow 를 시작합니다.
      }

      @Override
      protected void onPause() {
        super.onPause();
        background.removeUpdatable(this); // 저장소로부터 이벤트를 받지 않고 flow 가 중단되도록 합니다.
      }

      @Override
      public void update() {
        // Called as the repository is updated
        background.get().ifSucceededSendTo(this); // 만약 정상적인 Bitmap 이 있다면 accept() 로 전달합니다.
      }

      @Override
      public void accept(@NonNull Bitmap background) {
        backgroundView.setImageBitmap(background); // View 의 배경에 Bitmap 을 설정합니다.
      }
    }