Android/View | Posted by 덩치 2013.12.24 14:56

SurfaceView 구현 / 사용법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

SurfaceViewView를 상속받은 클래스로 Video Memory로 바로 접근하기 때문에 일반 View에서의 랜더링 

속도보다 빠르다.

일반 View는 많은 그리기 작업을 하면 메인 스레드의 자원을 다 잡아먹어버리기때문에 상당히 느려지게 되는데

이러한 단점을 보완하기 위한 클래스라고 보면 된다


우선 액티비티에 SurfaceHolder.Callback을 해 주고, add unimplemented methods를 해 준다.


public class DrawClass implements SurfaceHolder.Callback{


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}


@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);

return true;

}


@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}


@Override

public void surfaceCreated(SurfaceHolder holder) {

}


@Override

public void surfaceDestroyed(SurfaceHolder holder) {

}

}


그럼 셋팅은 끝. 사용되는건 surfaceCreatedsurfaceDestoryed 정도가 되겠다.

surfaceCreated는 처음 서피스뷰가 생성될 때 호출되는데, 주의할점은 백그라운드 상태로 내려갔다가, 다시 올라오게 되면

surfaceview가 다시 created된다는점이다. created에서 thread를 실행시키는 작업을 할 경우

반드시 스레드가 동작중인지 여부를 먼저 확인해야한다. 그렇지않으면 익셉션 발생


surfaceChanged는 업데이트를 대비해 만들었다, 뭐라뭐라 하던데 잘 모르겠다. 사용하지않는듯하다.


이제 SurfaceView 구성은 하였고, 실시간으로 그리기를 실행하려면 Thread를 구동해야한다.


private Class PaintThread extends Thread {

public void run() {

while(!this.isInterrupted()){    //스레드가 인터럽트 될 때까지 반복 실행.

if (그리기 실행조건) {

//그리기 실행

doDraw();

}

}

}

}


나는 주로 드로우 관련부를 따로 만들어서 호출하는방식으로 사용한다.

비트맵을 그려보겠다. surfaceCreated에 다음과 같이 선언한다. (그 위에 Bitmap img, tempBitmap 전역변수로 선언해둔다)

팁 하나, 비트맵 이미지가 큰 경우 메모리를 상당히 많이 잡아먹어 종종 익셉션이 발생하게 되는데,

BitmapFactory.Options option = new BitmapFactory.Options();

option.inSampleSize = 1;

option.inPurgeable = true;

option.inDither = true;

이렇게 해 주면 비트맵이 먹는 메모리를 줄일 수 있다. 리사이클만으로는 감당이 안되는 경우가 생겨 찾다보니 이렇게 해주니 해결되더라. 이렇게 했을경우 단점은 잘 모르겠다. 고퀄리티를 요하는 작업이 아니었기때문에..

그리고 

tempBitmap = BitmapFactory.decodeResource(res, R.drawable.img30x30, option);

img = Bitmap.createScaledBitmap(tempBitmap, imgWidth, imgHeight, true);


private void doDraw() {

try {

canvas = mHolder.lockCanvas(); //그리기 준비

     int size = MainActivity.ARR_X.size();

     canvas.drawColor(Color.GRAY);  //배경색 설정

Paint p = new Paint();

p.setAntiAlias(true);

     canvas.drawBitmap(img, imgX, imgY, p);  //이미지를 X,Y위치에 그리기

catch (Exception e) {

}

finally {

mHolder.unlockCanvasAndPost(canvas); //그리기 종료

}

}


그리고 MainActivityxml에서


<패키지명.DrawClass

android:layout_width="500px"

android:layout_height="500px" />

와 같은식으로 호출한다.


여기까지가 SurfaceView 사용 방법이다.


참고로 위의 소스는 새로운 클래스를 만들어서 기존 액티비티에 영역추가하는식으로 사용한것이고

뷰와 마찬가지로 액티비티에서 바로 setContentView하여 적용 할 수도 있다.

문의점은 댓글 남겨주기바람