'onWindowFocusChanged()'에 해당되는 글 1건

  1. 2013.09.25 [android] AnimationDrawable관련 주의점

[android] AnimationDrawable관련 주의점

android 2013. 9. 25. 14:08

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

android에서 animation은 크게 2가지로 구분된다.

Frame animation :

frame의 이미지를 여러장 준비해서 보여주는 것

장점 : 이미지 제작에 따라서 다양한 에니메이션이 가능하다

단점 : 이미지를 많이 쓰게되면, 저사양 단말에서 OutofMemory 발생 가능성이 높아진다.

Tween animation

시스템이 제공하는 방법으로 첫상태와 마지막 상태를 지정해서 중간의 frame은 계산해서 만드는방식

장점 : 이미지가 필요없어서 가볍고 빠르다.

단점 : 제공되는 animation만 가능하다. ( alpha, scale, translate 등등 )

 

이중에서 Frame Animaton을 이용할 때 AnimationDrawable을 사용하게 되는데 사용시 주의점에 대해서 몇가지 적어본다.

 

[ AnimationDrawable.start() 호출 시점 ]

사용자의 interaction 없이 Activity의 시작과 동시에 animation이 시작되야 할 때 onCreate에서 호출하면 동작을 않한다. 이유는 developer 사이트에서 다음과 같이 설명하고 있다.

It's important to note that the start() method called on the AnimationDrawable cannot be called during the onCreate() method of your Activity, because the AnimationDrawable is not yet fully attached to the window. If you want to play the animation immediately, without requiring interaction, then you might want to call it from the onWindowFocusChanged() method in your Activity, which will get called when Android brings your window into focus.

출처 : http://developer.android.com/guide/topics/graphics/drawable-animation.html

 

쉽게 말하면 onCreate에서는 window에 완전하게 붙은 상태가 아니라서, 완전히 붙은 시점인 onWindowFocusChanged()에서 호출해야 된다는 것이다. 구글링하다보면 아래와 같은 해결방법도 있다 

ImageView rocketImage = (ImageView) layout.findViewById(R.id.animation);

rocketImage.setBackgroundResource(R.drawable.progress_blue_animation);

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();

rocketImage.post(new Runnable(){

    public void run(){

        rocketAnimation.start();

    }

});

 ImageViewpost()를 통해서 호출시점을 조금 뒤로 늦추는 방식인데, 이 방식보다는 developer 페이지에서 언급한 방식이 더 낳아 보인다.

  

[ 3.0 미만에서 OutofMemory 이슈 ]

AnimationDrawable로 몇가지 만든다음에 반복적으로 실행하다보면 memory가 적은 단말에서 OutofMemory가 발생한다. 검색해보니 3.0 미만에서는 명시적으로 이미지리소스를 해제해주어야 한다. 해제하는 방법은 아래와 같다 

ad.stop();

for (int i = 0; i < ad.getNumberOfFrames(); ++i){

    Drawable frame = ad.getFrame(i);

    if (frame instanceof BitmapDrawable) {

        ((BitmapDrawable)frame).getBitmap().recycle();

    }

    frame.setCallback(null);

}

ad.setCallback(null);

 

참고로 3.0 이상에서 AnimationDrawable의 리소스를 해제하게되면 같인 리소스의 Animation을 2번 실행하면 recycledBitmap을 사용했다면서 crash가 발생한다. 아마도 3.0 이상부터는 bitmap이 java 영역의 heap에 할당 되면서 캐시가 되고 있는것 같은 느낌이다. 그래서 강제로 recycle을 호출하면 안된다. 

안드로이드 3.0만 되도 좋을 것 같은데.. 아직도 2.3의 사용비율이 전체에서 30%가 넘는구나..

 

[ 2013-10 에 추가 ] 

위에처럼 명시적으로 해제 할 경우에 문제가 발생한다.  아래의 방법이 더 잘 동작한다.  리소스아이디 0을 넘김으로써 빈   drawable을 선택하게 하면 기존에 가지고 있던 리소스가 자동으로 해제되는 방식으로 안드로이드 버전에 따른 문제도 없다. 

ad.stop();

ad.selectDrawable(0); 




: