- 작성시간 : 2011/07/05 11:18
- 퍼머링크 : jjunda.egloos.com/4998086
- 덧글수 : 0
http://ensider.tistory.com/trackback/2
안드로이드 폰내에 저장 음악 리스트를 보여주고 재생하는 앱을 만들어 보자.

그리고, onCreate 메소드에서 mListView의 객체를 얻고, ListView와 Adatper를 연결한다. 추가적으로 List를 클릭했을 때 음악을 연주 할 수 있도록 Listener를 등록한다.
playMusic 함수의 구현부는 아래와 같다. URI를 넘겨 받아 음악을 재생한다. 음악이 재생이 완료시에는 Listener를 등록하여 onCompletion이 호출되는데, 이 예제에서는 특별히 아무 동작도 하지 않는다.
MusicAdapter 클래스는 BaseAdapter로 부터 상속받아 정의하는데, 주요 역할은 MediaStotre API를 사용해 폰 내에 저장된 음악들을 스캔하고, ListView가 요청시 getView()에서 View를 생성해 리턴해 준다. 자세한 설명은 아래의 주석을 참조하자.

안드로이드 폰내에 저장 음악 리스트를 보여주고 재생하는 앱을 만들어 보자.
우선 Eclipse에서 다음과 같은 형태로 프로젝트를 생성한다.
우선 Eclipse에서 다음과 같은 형태로 프로젝트를 생성한다.
화면의 기본 구성은 ListView를 사용하며, ListView의 라인별로 Album Art와 Title, 가수를 보여주는 구조로 작성 할 것이다.
먼저 Project를 생성한 후에, layout/main.xml을 다음과 같이 수정한다. LinearLayout 안에 mylist라는 id의 ListView가 존재한다.
다음으로 ListView 안에 들어 갈 각 아이템의 Layout을 설정하기 위해 layout/item.xml을 다음과 같이 생성해 준다.
이 Layout 구성에서 볼 수 있듯이 각 아이템은 Horizontal 방향으로 Album Art를 표시하고, 다시 Vertical 방향으로 ImageView와 Title, 그리고 가수 이름을 표시할 TextView로 이루어 진다.
화면의 기본 구성은 ListView를 사용하며, ListView의 라인별로 Album Art와 Title, 가수를 보여주는 구조로 작성 할 것이다.
먼저 Project를 생성한 후에, layout/main.xml을 다음과 같이 수정한다. LinearLayout 안에 mylist라는 id의 ListView가 존재한다.
1 2 3 4 5 | <!--?xml version="1.0" encoding="utf-8"?--><LINEARLAYOUT android:paddingright="8dp" android:paddingleft="8dp" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <LISTVIEW android:layout_height="match_parent" android:layout_width="match_parent" android:id="@+id/mylist"> </LISTVIEW></LINEARLAYOUT> |
다음으로 ListView 안에 들어 갈 각 아이템의 Layout을 설정하기 위해 layout/item.xml을 다음과 같이 생성해 준다.
1 2 3 4 5 6 7 8 9 10 | <!--?xml version="1.0" encoding="UTF-8"?--><LINEARLAYOUT android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="horizontal" xmlns:android="http://schemas.android.com/apk/res/android"> <IMAGEVIEW android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/albumart"> <LINEARLAYOUT android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <TEXTVIEW android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/title" android:textstyle="bold" android:textcolor="#00ccff" android:padding="5dp"> <TEXTVIEW android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/singer" android:padding="5dp" android:textsize="12sp"> </TEXTVIEW></TEXTVIEW></LINEARLAYOUT> </IMAGEVIEW></LINEARLAYOUT> |
이 Layout 구성에서 볼 수 있듯이 각 아이템은 Horizontal 방향으로 Album Art를 표시하고, 다시 Vertical 방향으로 ImageView와 Title, 그리고 가수 이름을 표시할 TextView로 이루어 진다.
mainActivity에는 ListView를 얻을 변수와 MediaStore를 스캔해서 ListView와 연결 할 Adapter 멤버변수, 그리고 MediaPlayer 멤버변수를 추가한다.
1 2 3 4 | private ListView mListView; private MusicAdapter mMusicAdapter; private MediaPlayer mMediaPlayer = new MediaPlayer(); |
그리고, onCreate 메소드에서 mListView의 객체를 얻고, ListView와 Adatper를 연결한다. 추가적으로 List를 클릭했을 때 음악을 연주 할 수 있도록 Listener를 등록한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /-* Layout으로 부터 ListView에 대한 객체를 얻는다. *-/ mListView = (ListView)findViewById(R.id.mylist); mMusicAdapter = new MusicAdapter(this); mListView.setAdapter(mMusicAdapter); /- Listener for selecting a item *- mListView.setOnItemClickListener(new ListView.OnItemClickListener() { public void onItemClick(AdapterView<!--?--> parentView, View childView, int position, long id) { Uri musicURI = Uri.withAppendedPath( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, "" + mMusicAdapter.getMusicID(position)); playMusic(musicURI); } }); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public void playMusic(Uri uri) { try { mMediaPlayer.reset(); mMediaPlayer.setDataSource(this, uri); mMediaPlayer.prepare(); mMediaPlayer.start(); mMediaPlayer.setOnCompletionListener(new OnCompletionListener() { public void onCompletion(MediaPlayer mp) { // TODO // Do something when playing is completed } }); } catch (IOException e) { Log.v("SimplePlayer", e.getMessage()); } } |
MusicAdapter 클래스는 BaseAdapter로 부터 상속받아 정의하는데, 주요 역할은 MediaStotre API를 사용해 폰 내에 저장된 음악들을 스캔하고, ListView가 요청시 getView()에서 View를 생성해 리턴해 준다. 자세한 설명은 아래의 주석을 참조하자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /-*========================================== * Adapter class * ==========================================*- public class MusicAdapter extends BaseAdapter { private ArrayList<STRING> mMusicIDList; private ArrayList<STRING> mAlbumartIDList; private ArrayList<STRING> mMusiceTitleList; private ArrayList<STRING> mSingerList; private Context mContext; MusicAdapter(Context c){ mContext = c; mMusicIDList = new ArrayList<STRING>(); mAlbumartIDList = new ArrayList<STRING>(); mMusiceTitleList = new ArrayList<STRING>(); mSingerList = new ArrayList<STRING>(); getMusicInfo(); } public boolean deleteSelected(int sIndex){ return true; } public int getCount() { return mMusicIDList.size(); } public Object getItem(int position) { return position; } public long getItemId(int position) { return position; } public int getMusicID(int position) { return Integer.parseInt((mMusicIDList.get(position))); } public View getView(int position, View convertView, ViewGroup parent) { View listViewItem = convertView; if (listViewItem == null) { /-* Item.xml을 Inflate해 Layout 구성된 View를 얻는다. *-/ LayoutInflater vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); listViewItem = vi.inflate(R.layout.item, null); } /-* Album Art Bitmap을 얻는다. *-/ ImageView iv = (ImageView) listViewItem.findViewById(R.id.albumart); Bitmap albumArt = mainActivity.getArtworkQuick(mContext, Integer.parseInt((mAlbumartIDList.get(position))), 50, 50); iv.setImageBitmap(albumArt); /-* T-tle 설정 *-/ TextView tv = (TextView) listViewItem.findViewById(R.id.title); tv.setText(mMusiceTitleList.get(position)); /-* Singer 설정 *-/ TextView tv1 = (TextView) listViewItem.findViewById(R.id.singer); tv1.setText(mSingerList.get(position)); /-* 구성된 ListView Item을 리턴해 준다. *-/ return listViewItem; } private void getMusicInfo(){ /-* 이 예제에서는 단순히 ID (Media의 ID, Album의 ID)만 얻는다. *-/ String[] proj = {MediaStore.Audio.Media._ID, MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST }; Cursor musicCursor = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj, null, null, null); if (musicCursor != null && musicCursor.moveToFirst()){ String musicID; String albumID; String musicTitle; String singer; int musicIDCol = musicCursor.getColumnIndex(MediaStore.Audio.Media._ID); int albumIDCol = musicCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID); int musicTitleCol = musicCursor.getColumnIndex(MediaStore.Audio.Media.TITLE); int singerCol = musicCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST); do { musicID = musicCursor.getString(musicIDCol); albumID = musicCursor.getString(albumIDCol); musicTitle = musicCursor.getString(musicTitleCol); singer = musicCursor.getString(singerCol); /- Media ID와 Album ID를 각각의 리스트에 저장해 둔다 * *- mMusicIDList.add(musicID); mAlbumartIDList.add(albumID); mMusiceTitleList.add(musicTitle); mSingerList.add(singer); }while (musicCursor.moveToNext()); } musicCursor.close(); return; } } </STRING></STRING></STRING></STRING></STRING></STRING></STRING></STRING> |
위의 코드 중 아래와 같이 albumID로 부터 AlbumArt 비트맵을 생성하는 부분이 있는데,
mainActivity.getArtworkQuick(mContext, Integer.parseInt((mAlbumartIDList.get(position))), 50, 50);
/sdcard/audio/albumart 밑에 앨범 아이디 별로 앨범 이미지가 존재하는데 이 비트맵으로 부터 지정된 크기대로 Bitmap 객체를 생성해 내는 함수이다. (이 함수는 인터넷에서 찾은 코드이다.;)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /-* Album ID로 부터 Bitmap을 생성해 리턴해 주는 메소드 *-/private static final BitmapFactory.Options sBitmapOptionsCache = new BitmapFactory.Options(); // Get album art for specified album. This method will not try to // fall back to getting artwork directly from the file, nor will // it attempt to repair the database. private static Bitmap getArtworkQuick(Context context, int album_id, int w, int h) { // NOTE: There is in fact a 1 pixel frame in the ImageView used to // display this drawable. Take it into account now, so we don't have to // scale later. w -= 2; h -= 2; ContentResolver res = context.getContentResolver(); Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id); if (uri != null) { ParcelFileDescriptor fd = null; try { fd = res.openFileDescriptor(uri, "r"); int sampleSize = 1; // Compute the closest power-of-two scale factor // and pass that to sBitmapOptionsCache.inSampleSize, which will // result in faster decoding and better quality sBitmapOptionsCache.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor( fd.getFileDescriptor(), null, sBitmapOptionsCache); int nextWidth = sBitmapOptionsCache.outWidth >> 1; int nextHeight = sBitmapOptionsCache.outHeight >> 1; while (nextWidth>w && nextHeight>h) { sampleSize <<= 1; nextWidth >>= 1; nextHeight >>= 1; } sBitmapOptionsCache.inSampleSize = sampleSize; sBitmapOptionsCache.inJustDecodeBounds = false; Bitmap b = BitmapFactory.decodeFileDescriptor( fd.getFileDescriptor(), null, sBitmapOptionsCache); if (b != null) { // finally rescale to exactly the size we need if (sBitmapOptionsCache.outWidth != w || sBitmapOptionsCache.outHeight != h) { Bitmap tmp = Bitmap.createScaledBitmap(b, w, h, true); b.recycle(); b = tmp; } } return b; } catch (FileNotFoundException e) { } finally { try { if (fd != null) fd.close(); } catch (IOException e) { } } } return null; } |
이제 실행을 하면 아래와 같은 화면을 볼 수 있다.
실행 후 리스트에서 선택 시 음악을 재생하게 된다.



최근 덧글