프로그램/Android

안드로이드 mp3플레어어 만들기(2. Cursor를 이용하여 mp3 데이터 가져오기)

잡식성초보 2017. 8. 7. 15:29
오늘은 mp3파일 을 리스트를 들고와서 뿌려주는것을 할려고합니다. 

 mp3파일을 리스트로 뿌려주는 방법은 두가지가 있습니다. 

 첫번째는 안드로이드 기기 최상단에서부터  .mp3파일을 다 읽어와서 뿌려주는 방법이고 , 

두번째는 Cursor를 이용하여 mp3파일을 가져와서 데이터를 뿌려주는 방법입니다. 

 저는 Cursor를 이용하여 데이터를 가져올것인데요.

 Cursor를 사용하는 이유는 파일들을 읽어오면 그 파일들을 다시 metadata로 변환시켜 뽑아야하는 

불편함이 있기때문입니다. 


 1. Cursor를 이용하여 mp3파일 데이터를 얻어내는 방법입니다.




private void getMusicData(){ //1. 음악파일인지 아닌지, 2. 앨범 아이디, 3. 음원명, 4.가수명, 미디어 파일 아이디(?) String[] projection = { MediaStore.Audio.Media.IS_MUSIC, MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media._ID}; ContentResolver contentResolver = mContext.getContentResolver(); Cursor cursor = contentResolver.query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, // content://로 시작하는 content table uri projection, // 어떤 column을 출력할 것인지 null, // 어떤 row를 출력할 것인지 null, MediaStore.Audio.Media.TITLE + " ASC"); // 어떻게 정렬할 것인지 if(cursor != null) { while (cursor.moveToNext()) { try{ // MediaStore.Audio.Media.IS_MUSIC 값이 1이면 mp3 음원 파일입니다. // 그리고 밑에는 mp3 metadata 이미지 파일의 uri값을 얻어낸것입니다. // 이렇게 얻어낸 데이터를 arraylist에 저장합니다. if(cursor.getInt(0) != 0) { Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart"); Uri uri = ContentUris.withAppendedId(sArtworkUri, Integer.valueOf(cursor.getString(1))); MusicData data = new MusicData(); data.setMusicImg(uri); data.setMusicTitle(cursor.getString(2)); data.setSinger(cursor.getString(3)); data.setAlbumId(cursor.getString(1)); data.setMusicId(cursor.getString(4)); list.add(data); runOnUiThread(new Runnable() { @Override public void run() { adapter.setAdapterList(list); } }); } }catch (Exception e){ e.printStackTrace(); }



2. 두번째는 List를 adapter에 넘겨줘서 뿌려주기만 하면 됩니다. 하지만 여기서 많은 문제가 


초례합니다. 

안드로에드에서 ListView에 ImageView가 많이 있을경우 스크롤시에 엄청난 과부하가 생깁


니다. 다른곳에서 Listview에 대하여 검색을 하여 보면 리스트뷰는 뷰를 재사용한다고 뭐라고 


뭐라고 등등 합니다. 

어찌됫든 그리하여 과부하가 생기므로 성능을 최적화 시켜주는 방법인 ViewHolder를 이용하


여 줍니다. 하지만 이런 방법을 사용하여도 해결이 되지 않아서 저는 다른 Library를 이용하여 


ImageView때문에 걸려오는 과부하를 처리하였습니다. 


저의 Adapter뷰는 아래와 같습니다.(이전 소스는 몇가지 빼고 올렸었습니다...) 




public class MusicAdapter extends ArrayAdapter<MusicData>{
 
    private ArrayList<MusicData> item;
    private Context mContext;
    private ImageLoader loader;
    private btnClickListener listener;
 
    public interface btnClickListener {
        void MusicBtnClick(int position);
    }
 
    public void setMusicBtnListener(btnClickListener l) {
        listener = l;
    }
 
    public MusicAdapter( Context context, int resource,  ArrayList<MusicData> item) {
        super(context, resource, item);
        this.mContext = context;
        this.item = item;
 
        //이미지 로더 init
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(mContext)
                .threadPriority(10)
                .denyCacheImageMultipleSizesInMemory()
                .diskCacheFileNameGenerator(new Md5FileNameGenerator())
                .tasksProcessingOrder(QueueProcessingType.LIFO)
                .writeDebugLogs()
                .build();
 
        loader = ImageLoader.getInstance();
        loader.init(config);
 
    }
 
    public void setAdapterList(ArrayList<MusicData> list){
        item = list;
        notifyDataSetChanged(); //Listview Refresh 기능
    }
 
 
    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
 
        ViewHolder holder;
        View v = convertView;
        if(v == null){
            LayoutInflater vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.row_music_list, null);
 
            holder = new ViewHolder();
            holder.img = v.findViewById(R.id.imgMusic);
            holder.title = v.findViewById(R.id.txt_music_title);
            holder.name = v.findViewById(R.id.txt_singer_name);
            holder.btn =v.findViewById(R.id.isMusic_click);
 
            v.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
 
        final MusicData data = item.get(position);
        if(data != null){
 
            if(data.getMusicImg() != null){
 
                DisplayImageOptions options = new DisplayImageOptions.Builder()
                        .showImageForEmptyUri(R.drawable.musical_note) // Uri주소가 잘못되었을경우(이미지없을때)
                        .resetViewBeforeLoading(false)  // 로딩전에 뷰를 리셋하는건데 false로 하세요 과부하!
                        .cacheInMemory(true) // 메모리케시 사용여부
                        .cacheOnDisc(true) // 디스크캐쉬를 사용여부(사용하세요왠만하면)
                        .build();
 
                loader.displayImage(data.getMusicImg().toString(), holder.img, options);
 
            } else{ //이미지가 없을 경우가 있으므로 default image
                holder.img.setBackgroundResource(R.drawable.musical_note);
            }
 
            holder.title.setText(data.getMusicTitle());
            holder.name.setText(data.getSinger());
            holder.btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    listener.MusicBtnClick(position);
                }
            });
        }
 
        return v;
    }
 
    class ViewHolder {
 
        ImageView img;
        TextView title;
        TextView name;
        Button btn;
    }
}



3. 위에서 사용한 라이브러리는 이미지로더, 그리고 이미지등을 사용하므로 혹시나 해서 


manifest에 밑에 두가지 기능을 true로 넣어줬습니다.


이미지로더 라이브러리를 사용하지 않고 mp3파일 리스트를 뽑아서 스크롤링 하여보면 엄청


난 버벅거림을 느낄수 있을것입니다...




android:hardwareAccelerated="true"
android:largeHeap="true"
 
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'


반응형