[NoSQL/Cassandra] PHPCassa 에서 TimeUUIDType을 어떻게 활용하는가?

사용자 삽입 이미지
별거 아닌 내용을 적어보려고 합니다. 하지만 처음 접할때 생각보다 어려웠던 기억이 나는군요. 이 글을 보시기 전에 PHPCassa에 대한 이해가 필요합니다. [이글]을 먼저 보시길 추천합니다.

Cassandra에는 기본적으로 TimeUUIDType이라는 것이 존재합니다. 이 타입을 이용하여 여러개의 컬럼키들을 시간순으로 정렬하는것이 가능해집니다. 기존의 MySQL등에서는 Auto Increment 옵션을 사용하여 Unique한 PK를 만들어냅니다만 Cassandra에서는 이 TimeUUIDType을 이용하여 사실상 거의 중복되지 않는 키값을 만들어 낼 수 있습니다.

그렇다면 이제 이 키값을 이용하여 서버-클라이언트간에 주고 받을 수 있어야 하는데요, 이것이 생각보다 간단하지 않습니다.(사실 알고보면 간단합니다만;) 우선 소스코드부터 보여드리겠습니다.
[code]// 1. 새로운 UUID를 생성
$newUUID = CassandraUtil::uuid1();
echo “<p>새로운 UUID생성: $newUUID</p>”;

// 2. 클라이언트/서버와 주고받을때 사용할 수 있는 문자형태로 변환
$strUUID = strval(CassandraUtil::import($newUUID));
echo “<p>식별가능한 문자열UUID로 변경: $strUUID</p>”;

// 3. 다시 바이너리 형태의 UUID로 변경
$importedUUID = CassandraUtil::import($strUUID)->bytes;
echo “<p>바이너리 형태의 UUID로 변경: $importedUUID</p>”;[/code]
위의 코드는 현재의 시간(64bit microtime)을 이용하여 UUID를 생성한 다음 그것을 서버-클라이언트간에 식별하기 쉬운 문자열로 바꾼후에 다시 그 문자열을 Cassandra에서 바로 사용할 수 있는 형태로 되돌리는 과정을 수행합니다. 위의 코드는 아래와 같은 결과를 보여줍니다.

사용자 삽입 이미지
첫번째와 마지막이 사실상 같다는 것을 알 수 있습니다. Cassandra에서는 기본적으로 이 Binary형태의 값을 사용합니다. 하지만 개발자가 사용하기 어렵고 이렇게 생성된 값을 서버/클라이언트간 주고 받는다고 해도 생각해볼점이 많아집니다. 이 경우 두번째와 같은 형태로 변경하여 사용할 수 있습니다.

[Android] 애니메이션의 시작과 끝을 고민할 필요없는 AnimatedImageView 만들기

anim_1.pnganim_2.png anim_3.png
허접한 감이 없잖아 있지만 생각보다 다수의 이미지를 순차적으로 화면에 보여주는 애니메이션을 안드로이드에서 구현하기 위해서는 생각할 점이 많습니다. 제가 해보려는것의 위의 단순한 3개의 이미지를 반복해서 순차적으로 보여줄려는 것인데요 생각보다 복잡합니다.

/**
 * @author Eye
 */
public class AnimatedImageViewActivity extends Activity
{
private ImageView mIvAnimation;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // 에니메이션을 구동하기 위한 이미지뷰를 가져와 애니메이션을 세팅합니다.
        mIvAnimation = (ImageView) findViewById(R.id.animation);
        mIvAnimation.setBackgroundResource(R.anim.anim);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);

        // 배경이미지로 등록된 Drawable을 가져와 애니메이션을 시작합니다.
        AnimationDrawable adAnimatedDrawable =
            (AnimationDrawable) mIvAnimation.getBackground();
        adAnimatedDrawable.start();
    }
}

이 글은 애니메이션 자체에 대해 쓴 글이 아니기 때문에 처음부터 끝까지의 내용을 적지는 않겠습니다. 다만 예제 소스를 그대로 올릴테니 궁금하시면 열어보세요.

자 위의 코드를 한번 봐보겠습니다. 이미지뷰를 findViewById를 이용하여 가져온 뒤에 setBackgroundImage를 이용하여 마치 평소의 이미지를 세팅하는것처럼 이미지를 설정합니다.

곧바로 애니메이션을 실행하고 싶지만 onCreate에서는 에니메이션을 플레이 할 수 없습니다. 그래서 위의 예제에서는 onWindowFocusChanged라는 메소드를 구현하여 그안에 애니메이션을 시작하는 코드를 넣었는데요. getBackground를 통해 얻은 Drawable객체를 AnimationDrawable객체로 캐스팅한 후에 start를 하고 있는것을 알 수 있습니다.

[예제 다운로드]

위의 예제를 실행해 보면 일단 애니메이션이 매우 잘 실행이 됩니다. 하지만 매우 많은 애니메이션을 처리해야 한다거나 적절한 시점에 애니메이션이 플레이되고 정지되어야 하고 적절하게 메모리에서 제거가 되어야 한다면 어떻게 해야 할까요?

아마도 그 모든것을 관리하는 로직을 생각하여 프로그램을 짜야 할 것입니다. 하지만 이 모든것을 자동으로 처리해 주는 방법을 구현해 보겠습니다.

AnimatedImageView.java

/**
 * 화면에 보여질때 자동으로 시작하고 보이지 않을때 중단되는
 * 에니메이션이미지뷰입니다. 
 * 
 * @author Eye
 */
@RemoteView
public class AnimatedImageView extends ImageView
{
private AnimationDrawable mAnim;
private boolean mAttached;

/**
* 기본 생성자
* 
* @param context 컨텍스트
*/
public AnimatedImageView(Context context)
{
super(context);
}

/**
* 기본 생성자
* 
* @param context 생성자
* @param attrs 속성들
*/
public AnimatedImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
}

/**
* 애니메이션을 변경하고 시작합니다.
*/
private void updateAnim()
{
Drawable drawable = getDrawable();
if(mAttached && mAnim != null)
{
mAnim.stop();
}
if(drawable instanceof AnimationDrawable)
{
mAnim = (AnimationDrawable)drawable;
if (mAttached)
{
mAnim.start();
}
}
else
{
mAnim = null;
}
}

@Override
public void setImageDrawable(Drawable drawable)
{
super.setImageDrawable(drawable);
updateAnim();
}

@Override
public void setImageResource(int resid)
{
super.setImageDrawable(null);
super.setImageResource(resid);
updateAnim();
}

@Override
public void onAttachedToWindow()
{
super.onAttachedToWindow();
if (mAnim != null)
{
mAnim.start();
}
mAttached = true;
}

@Override
public void onDetachedFromWindow()
{
super.onDetachedFromWindow();
if (mAnim != null)
{
mAnim.stop();
}
mAttached = false;
}

@Override
protected void finalize() throws Throwable
{
clearAnimation();
super.finalize();
}
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<kr.pe.theeye.animatedimageview.AnimatedImageView
android:id="@+id/animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</LinearLayout>

위와 같은 변경으로 인해 이제 우리의 코드는 아래와 같이 단순해졌습니다. 아래가 전부입니다.

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// 에니메이션을 구동하기 위한 이미지뷰를 가져와 애니메이션을 세팅합니다.
mIvAnimation = (AnimatedImageView) findViewById(R.id.animation);
mIvAnimation.setImageResource(R.anim.anim);
}

이제부터는 저 이미지뷰가 화면에 보이게 되면 자동으로 애니메이션이 시작되며 화면에 보이지 않게 될 경우 자동으로 애니메이션이 정지됩니다. 또한 많은 애니메이션을 로드해도 적절한 시기에 메모리 반환을 최대한 할수 있도록 노력하였습니다. (하지만 생각만큼 완벽하진 않습니다. 능력 미달…) 아무튼 잘 되는 것을 보실 수 있습니다. 완성된 예제를 올려두겠습니다.

[예제다운로드]