헬로, 안드로이드 7 주차 멀티미디어 강대기동서대학교컴퓨터정보공학부
학습목표 오디오를재생하는방법에대해알아본다. 비디오를재생하는방법에대해알아본다. 스도쿠게임에음향효과를추가해본다. 2D 그래픽을심화학습하기위해, 커스텀뷰에대해학습하고이벤트핸들링과연결해본다.
차례 오디오재생하기 비디오재생하기 스도쿠에음향추가하기 커스텀뷰 이벤트핸들링 요약 퀴즈 연습문제
오디오재생하기 android.media 패키지안의 MediaPlayer 클래스를통해소리와음악의출력을지원함 사운드는가장쉽게는윈도우의녹음기 (Sound Recorder) 를통해생성할수있음 새프로젝트생성 Project name Audio Package name org.example.audio Activity name Audio Application name Audio
오디오재생하기 사운드파일을프로젝트의 res/raw 디렉토리안에복사함 res 디렉토리에파일이복사되면, 안드로이드이클립스플러그인이자동으로 R 클래스에자바기호를정의함 Audio 액티비티를코딩 각사운드마다새 MediaPlayer 인스턴스를선언하고, oncreate() 메서드안에서초기화함
Audio 액티비티의오디오재생부분 @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); } // Native rate is 44.1kHz 16 bit stereo, but // to save space we just use MPEG-3 22kHz mono up = MediaPlayer.create(this, R.raw.up); down = MediaPlayer.create(this, R.raw.down); left = MediaPlayer.create(this, R.raw.left); right = MediaPlayer.create(this, R.raw.right); enter = MediaPlayer.create(this, R.raw.enter); a = MediaPlayer.create(this, R.raw.a); s = MediaPlayer.create(this, R.raw.s); d = MediaPlayer.create(this, R.raw.d); f = MediaPlayer.create(this, R.raw.f);
오디오재생하기 다른방법으로는 MediaPlayer 인스턴스를선언하고이를재사용하는것으로, 서로다른사운드들의겹치기 (overlap) 을방지함 ( 겹치기는필요할때도있고필요하지않을때도있음 ) 사운드가필요할때마다새로 MediaPlayer 인스턴스를만드는방법도있으나, 실제안드로이드시스템에서는구현상의문제로불가능함. 프로그램의실행이지연되거나프로그램이크래시 (crash) 됨 참고로, 녹음을하려면 MediaRecorder 클래스를사용함
키눌림을감지하여사운드재생 Activity.onKeyDown() 메서드를오버라이드하여구현함 처음의 switch 부분은사용자가누른키에적합한미디어플레이어를선택하는부분 선택한후에, seekto() 메서드를불러소리를되감기 (rewind) 하고 start() 메서드로재생함 여기서 start() 는비동기메서드이므로사운드의재생시간에관계없이바로제어가프로그램으로반환됨 setoncompletionlistener() 를사용하여사운드클립이완료되면통보받음
Audio 액티비티의키눌림감지부분 @Override public boolean onkeydown(int keycode, KeyEvent event) { MediaPlayer mp; switch (keycode) { case KeyEvent.KEYCODE_DPAD_UP: mp = up; break; case KeyEvent.KEYCODE_DPAD_DOWN: mp = down; break; case KeyEvent.KEYCODE_DPAD_LEFT: mp = left; break; case KeyEvent.KEYCODE_DPAD_RIGHT: mp = right; break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: mp = enter; break; case KeyEvent.KEYCODE_A: mp = a; break; case KeyEvent.KEYCODE_S: mp = s; break; case KeyEvent.KEYCODE_D: mp = d; break; case KeyEvent.KEYCODE_F: mp = f; break; default: return super.onkeydown(keycode, event); } mp.seekto(0); mp.start(); return true; }
디버깅기술 안드로이드의 MediaPlayer 는변하기쉽고불안정함 메서드순서가바뀌거나인식할수없는형식이전달되는등의사소한문제로도크래쉬됨 왜냐하면 MediaPlayer 는 Java 층이얇은원시응용프로그램으로성능은빠르나오류가많기때문 리눅스의프로세스보호기능으로에뮬레이터 ( 또는폰 ) 과다른애플리케이션들은정상실행됨 개발과정중에진단정보를얻기위해서는, 안드로이드시스템로그에출력되는메시지 (message) 와트레이스백 (traceback) 을보는방법이있음 이클립스의로그캣 (LogCat) 뷰나 adb logcat 명령을사용함
안드로이드가지원하는오디오형식 WAV (PCM 압축되지않음 ) AAC ( 아이팟포맷, 보호안됨 ) MP3 (MPEG-3) WMA (Windows Media Audio) AMR ( 음성코덱 ) OGG (Ogg Vorbis) MIDI ( 악기 ) 대부분의에뮬레이터에서제대로동작하는포맷은 OGG, WAV 와 MP3 포맷임 기본오디오포맷은 44.1 KHZ, 16 비트스테레오오디오 MP3 의경우, 음성은모노, 음악은스테레오 OGG 의경우, 게임음향효과와같은짧은클립에적합함
비디오재생하기 비디오란결국여러장의사진이계속보여지며, 음성도동기화됨 MediaPlayer 가오디오와유사한방식으로비디오에적용될수있음. 다만, 개발자가이미지를그릴 surface ( 표면 ) 이필요함. start() 와 stop() 메서드로미디어재생을제어함 MediaPlayer 대신 VideoView 클래스로더간단히비디오를임베딩할수있음
안드로이드가지원하는비디오형식 MP4 (MPEG-4 낮은비트속도 ) H.263 H.264 (AVC) 윈도우 SDK 상에서는 MP4 만이안정적으로동작했음
VideoView 클래스로비디오를임베딩 새로운프로젝트를만듦 레이아웃변경 oncreate() 메서드수정 VideoView 클래스의 setvideopath() 메서드로파일을열고화상비율을유지하면서크기를컨테이너에맞춘후재생 재생할파일을업로드 AndroidManifest.xml 에적절한테마설정
레이아웃변경 <FrameLayout xmlns:android="http://schemas.android.com/a pk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <VideoView android:id="@+id/video" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center" /> </FrameLayout>
Video.java 의 oncreate() 메서드수정 @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); // Fill view from resource setcontentview(r.layout.main); VideoView video = (VideoView) findviewbyid(r.id.video); } // Load and start the movie video.setvideopath("/sdcard/samplevideo.3gp"); video.start();
재생할파일업로드 커맨드라인에서 adb 로올리거나, 안드로이드의파일익스플로러 (File Explorer) 를이용하여이클립스에파일을업로드또는다운로드 C:\> adb push c:\code\samplevideo.mp4 /data/samplevideo.mp4 안드로이드는파일확장명에상관하지않음
AndroidManifest.xml 에적절한테마 설정 비디오가제목줄과상태줄을포함한전체화면을차지하게테마설정 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.video" android:versioncode="1" android:versionname="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".video" android:label="@string/app_name" android:theme="@android:style/theme.notitlebar.fullscreen"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> </application> <uses-sdk android:minsdkversion="3" /> </manifest>
화면을회전하면비디오가다시시작되 는이유 기본적으로안드로이드는사용자의프로그램이화면회전에대해전혀모른다고가정함 리소스변경내용을감지하기위해안드로이드는액티비티를전부제거하고처음부터다시만듦 즉, oncreate() 가다시호출되고비디오가다시시작됨을의미함 이러한작동방식은많은애플리케이션에서문제가없으므로, 개발자들은신경쓰지않아도되고, 애플리케이션의생명주기와상태저장 / 복원을테스트하는유용한방법이될수있음
전환을부드럽게최적화하는방법 ondestroy() 와 oncreate() 에걸쳐유지되는데이터가저장된 onretainnonconfigurationinstance() 메서드를액티비티안에구현하여현재의인텐트와실행중인스레드의참조등을포함한모든것들을저장. 정보를되찾으려면액티비티의새인스턴스에 getlastnonconfigurationinstance() 를사용 AndroidManifest.xml 안의 android:configchange 속성을사용해서처리가능한변경내용을안드로이드에게알림
스도쿠에음향추가하기 메인액티비티 (Sudoku.java) 에음악을추가하려면, onresume() 과 onpause() 메서드를오버라이드 onresume() 는액티비티와사용자가상호작용을할때호출되므로, 여기서 Music 클래스를 start() R.raw.main() 은 /raw/main.mp3 를참조함 새액티비티를 resume 하기전에현액티비티를 pause 함. 스도쿠에서는새게임을시작시키면, Sudoku 액티비티가 pause 되고, Game 액티비티가시작됨 사용자가 Back 버튼이나 Home 버튼을누를때도 onpause() 가호출됨. Sudoku 액티비티에서는, 이때타이틀음악을멈춰야하므로, 여기서 Music.stop() 게임액티비티 (Game.java) 에서도 onresume() 과 onpause() 메서드를오버라이드
Sudoku.java @Override protected void onresume() { super.onresume(); Music.play(this, R.raw.main); } @Override protected void onpause() { super.onpause(); Music.stop(this); }
Game.java @Override protected void onresume() { super.onresume(); Music.play(this, R.raw.game); } @Override protected void onpause() { super.onpause(); Log.d(TAG, "onpause"); Music.stop(this); // Save the current puzzle getpreferences(mode_private).edit().putstring(pref_puzzle, topuzzlestring(puzzle)).commit(); }
Music 클래스 play() play() 메서드는 stop() 메서드를호출하여현재재생되는음악을멈춤 MediaPlayer.create() 를사용해서새로운 MediaPlayer 인스턴스를생성하고컨택스트와리소스 ID 를전달 만들어진인스턴스는음악을반복하도록옵션을설정한후재생함 stop() MediaPlayer 인스턴스가있는지확인하고 stop() 과 release() 메서드를호출함 stop() 메서드는음악을정지시키며, release() 메서드는 MediaPlayer 인스턴스와관련된시스템리소스를풀어줌 MediaPlayer 는자바가아닌원시 (primitive) 코드와관련이많은리소스이므로, GC 가회수할때까지기다릴수없음, 따라서 release() 를빠뜨리면에러가발생할수있음
Music.java import android.content.context; import android.media.mediaplayer; public class Music { private static MediaPlayer mp = null; /** Stop old song and start new one */ public static void play(context context, int resource) { stop(context); // Start music only if not disabled in preferences if (Settings.getMusic(context)) { mp = MediaPlayer.create(context, resource); mp.setlooping(true); mp.start(); } } /** Stop the music */ public static void stop(context context) { if (mp!= null) { mp.stop(); mp.release(); mp = null; } } }
자신만의커스텀뷰만들기 ( 여기서는 RobotView) 1. 프로젝트생성 2. 이미지추가 3. RobotView 클래스추가 android.view.view 확장 4. RobotView() 생성자추가 5. OnDraw(), OnSizeChanged() 6. 터치스크린처리 ; OnTouchEvent() 7. 키입력처리 ; OnKeyDown() 출처 한백전자의 Real H/W 기반안드로이드응용
새프로젝트생성 Project Name : TestCustomView Package Name : hanback.example Activity Name : TestCustom Application Name : Custom View Test
Import / General /File System 으로파일추가
RobotView 클래스추가 Package : hanback.example Name : RobotView Superclass : android.view.view Source / Generate Constructors from Superclass 로생성자추가 View(Context, AttributeSet) 선택 Source / Override/Implement Methods ondraw(canvas) 선택
생성된코드
main.xml 에커스텀뷰추가
코드추가
실행결과
소스코드수정
실행결과
터치이벤트처리 ontouchevent(motionevent) 추가
터치이벤트를위한코드수정 x, y 변수를 RobotView 의멤버변수로뺌 ontouchevent() 함수작성 & 실행확인
초기화시화면가운데이미지위치 onsizechanged(int, int, int,int) 추가
코드수정 1 screenwidth, screenheight 멤버변수로. width, height 멤버변수로 멤버함수수정
코드수정 2
키이벤트처리하기 onkeydown(int, KeyEvent) 추가
소스코드추가
Java 코드 (Code) 에서뷰 (View) 다루기 (http://www.mobileplace.co.kr/2353) id 1. <TextView 2. android:id="@+id/text" 3. android:layout_width="fill_parent" 4. android:layout_height="wrap_content" 5. /> Code 1. TextView t = (TextView)findViewById(R.id.text); 2. t.settext("hello"); 3. t.setbackgroundcolor(0xffff0000); 4. t.setgravity(gravity.left);
View.onClickListener 1. Button button = (Button)findViewById(R.id.button); 2. button.setonclicklistener(new View.OnClickListener() { 3. public void onclick(view v) { 4. //Code 5. } 6. });
요약 오디오를재생하는방법에대해알아보았다. 비디오를재생하는방법에대해알아보았다. 스도쿠게임에음향효과를추가해보았다. 2D 그래픽을심화학습하기위해, 커스텀뷰에대해체계적으로학습하고이벤트핸들링과연결했다.
퀴즈 오디오를재생하려면어떤클래스를사용해야하는가? 비디오를재생하려면어떤클래스를사용해야하는가? 다른방법은뭐가있는가? 앞의슬라이드에서 View 의 onclicklistener() 를구현하는방법을보면, setonclicklistener 를이용하여직접코드를집어넣는방법을사용하고있다. 새로운클래스를만들어서 Listener 메서드들만따로관리하는방법은없을까? 동영상변환툴 ( 예, Badak) 을이용하여기존의동영상을변환해서안드로이드에서실행시켜보자.
연습문제 자신이가지고있는 MP3 파일을재생하는프로그램을작성해보자. 여러 MP3 파일리스트들을보여주면서, 선택할경우, 재생시켜주는프로그램을작성해보자. 화면에특정이미지를보여주면서그이미지에알맞은음악을재생하다가, 키를누르면다른이미지를보여주면서그이미지에맞는음악을재생해주는프로그램을작성하라. 동영상변환툴 ( 예, Badak) 을이용하여기존의동영상을변환해서안드로이드에서실행시켜보자.
심화연습문제및프로젝트아이디어 대부분의응용프로그램들은서비스를이용하여음악을재생한다. 서비스를이용하여음악을재생하는프로그램을작성해보라. 다음의스도쿠변종게임들을조사해보고, 어떤게임들인지간단히설명해보라. Kakuro Killer sudoku Jigsaw Sudoku puzzle nonomino Mini Sudoku Hypersudoku Gattai 5 Greater Than Sudoku