zoukankan      html  css  js  c++  java
  • 实现本地音乐选择,播放,带可拖动进度条

    需求:项目需要实现扫描本地sdcard上的所有音乐.并且可以进行播放,带可拖动进度条。

    实现步骤:1.每个音乐文件在数据中有一条记录,开启一个线程查找数据库找出所有音乐文件,根据后缀名进行过滤,用handle通知ListView展示

                      2.ListView每一行设置单击事件,选中的那首歌曲进行播放。

                      3.ListView每一行都有seekBar,根据item选中进行显示隐藏。

    1. activity文件 SelectMusicActivity.java

    public class SelectMusicActivity extends Activity{
    	private final static int MUSIC_SCARCH_FINISH = 1;//音乐扫描完成
    	
    	private ProgressDialog mProgressDialog;
    	private List<MusicFile> musicFiles=new ArrayList<MusicFile>();
    	private ListView listMusic;
    	private MyAdapter myAdapter;
    	
    	private boolean isPlaying;//是否正在播放
    	private int currentPosition = -1;
    	private ViewHolder currentHolder;
    	
    	private MediaPlayer mediaPlayer=new MediaPlayer();//音乐播放工具
    	
    	private Handler mHandler=new Handler(){
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case MUSIC_SCARCH_FINISH://音乐扫描完成
    				mProgressDialog.dismiss();
    				listMusic.setAdapter(myAdapter=new MyAdapter());
    				break;
    			}
    		};
    	};
    	
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_select_music);
    		getMusicFloder();//查询本地所有音乐
    		
    		listMusic=(ListView) findViewById(R.id.list_music);
    	}
    	
    	@Override
    	protected void onDestroy() {
    		super.onDestroy();
    		if(null!=mediaPlayer){
    			mediaPlayer.release();
    			mediaPlayer=null;
    			isPlaying=false;
    		}
    	}
    	
    	//-------------------------私有类   私有方法---------------------
    	private class MyAdapter extends BaseAdapter{
    		@Override
    		public int getCount() {
    			// TODO Auto-generated method stub
    			return musicFiles.size();
    		}
    
    		@Override
    		public Object getItem(int position) {
    			// TODO Auto-generated method stub
    			return musicFiles.get(position);
    		}
    
    		@Override
    		public long getItemId(int position) {
    			// TODO Auto-generated method stub
    			return position;
    		}
    
    		@SuppressLint("ResourceAsColor")
    		@Override
    		public View getView(final int position, View convertView, ViewGroup parent) {
    			final ViewHolder holder;
    			if(null==convertView){
    				holder=new ViewHolder();
    				convertView = LayoutInflater.from(SelectMusicActivity.this).inflate(R.layout.item_music_file,parent,false);
    				holder.musicInfo=(LinearLayout) convertView.findViewById(R.id.music_info);
    				holder.ivPlayState=(ImageView) convertView.findViewById(R.id.iv_play_state);
    				holder.musicFolderName=(TextView) convertView.findViewById(R.id.music_folder_name);
    				holder.musicDuration=(TextView) convertView.findViewById(R.id.music_duration);
    				
    				holder.rlMusicCapture=(RelativeLayout) convertView.findViewById(R.id.rl_music_capture);
    				holder.sbProgress=(SeekBar) convertView.findViewById(R.id.sb_progress);
    				holder.txtStartTime=(TextView) convertView.findViewById(R.id.txt_start_time);
    				holder.txtEndTime=(TextView) convertView.findViewById(R.id.txt_end_time);
    				convertView.setTag(holder);
    			}else{
    				holder=(ViewHolder) convertView.getTag();
    			}
    			
    			MusicFile musicFile=musicFiles.get(position);
    			holder.musicFolderName.setText(musicFile.getName().substring(1));
    			holder.musicDuration.setText(Utils.getMusicDuration(musicFile.getMusicDuration()));
    			holder.txtEndTime.setText(Utils.getMusicDuration(musicFile.getMusicDuration()));
    			holder.sbProgress.setMax(musicFile.getMusicDuration());
    			
    			if (position == currentPosition) {
    				holder.rlMusicCapture.setVisibility(View.VISIBLE);
    				
    				holder.musicInfo.setBackgroundColor(R.color.mainColor);
    			}else{
    				holder.rlMusicCapture.setVisibility(View.GONE);
    				holder.musicInfo.setBackgroundColor(android.R.color.white);
    			}
    			
    			holder.musicInfo.setOnClickListener(new OnClickListener(){
    				@Override
    				public void onClick(View v) {
    					itemClick(holder,position);
    				}
    			});
    			
    			holder.sbProgress.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
    				@Override
    				public void onStopTrackingTouch(SeekBar seekBar) {}
    				@Override
    				public void onStartTrackingTouch(SeekBar seekBar){}
    				@Override
    				public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {
    					if(fromUser){
    						if(mediaPlayer != null && isPlaying){
    							mediaPlayer.seekTo(progress);
    							holder.txtStartTime.setText(Utils.getMusicDuration(progress));
    						}
    					}
    				}
    			});
    			return convertView;
    		}
    	}
    	
    	/**
    	 * 相当于List的点击事件
    	 * @param holder
    	 * @param position
    	 */
    	@SuppressLint("ResourceAsColor")
    	private  void itemClick(ViewHolder holder,int position){
    		MusicFile musicFile=musicFiles.get(position);
    		if(position==currentPosition){//选中当前歌曲
    			if(isPlaying){//播放中
    				holder.ivPlayState.setImageResource(R.drawable.button_music_normal);
    				mediaPlayer.pause();
    				isPlaying=false;
    				
    				//position=-1的时候会隐藏下面的seekbar  并且背景颜色设置成白色
    				position = -1;
    				myAdapter.notifyDataSetChanged();
    			}else{//暂停中
    				holder.ivPlayState.setImageResource(R.drawable.button_music_selected);
    				mediaPlayer.start();
    				isPlaying=true;
    			}
    		}else{//选中其他歌曲
    			if(currentPosition==-1){//第一次选中歌曲
    				holder.ivPlayState.setImageResource(R.drawable.button_music_selected);
    				musicPlay(musicFile.getDir());
    			}else{
    				musicPlay(musicFile.getDir());
    				
    				currentHolder.ivPlayState.setImageResource(R.drawable.button_music_normal);
    				holder.ivPlayState.setImageResource(R.drawable.button_music_selected);
    			}
    		}
    		currentPosition = position;
    		myAdapter.notifyDataSetChanged();
    		currentHolder=holder;
    	}
    	
    	private  class ViewHolder{
    		private LinearLayout musicInfo;
    		private ImageView ivPlayState;
    		private TextView musicFolderName;
    		private TextView musicDuration;
    		
    		private RelativeLayout rlMusicCapture;//播放截取
    		private SeekBar sbProgress;//截取进度条
    		private TextView txtStartTime;//截取开始时间
    		private TextView txtEndTime;//截取结束时间
    	}
    	
    	/**
    	 * 播放歌曲
    	 */
    	private void musicPlay(String musicFile){
    		try {
    			mediaPlayer.reset();
    			mediaPlayer.setDataSource(musicFile);
    			mediaPlayer.prepare();
    			mediaPlayer.start();
    			isPlaying = true;
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	
    	/**
    	 * 利用ContentProvider扫描手机中的音乐,此方法在运行在子线程中完成音乐的扫描,获取所有音乐文件
    	 */
    	private void getMusicFloder() {
    		if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    			Toast.makeText(this, "没有sdcard", 0).show();
    			return;
    		}
    		// 显示进度条
    		mProgressDialog = ProgressDialog.show(this,null,"正在加载中");
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				//查询音乐
    				Uri mImageUri = Media.EXTERNAL_CONTENT_URI;
    				ContentResolver mContentResolver = SelectMusicActivity.this.getContentResolver();
    				String selection=Media.MIME_TYPE + "=? ";
    				String[] selectionArgs=new String[]{"audio/mpeg"};
    				Cursor mCursor = mContentResolver.query(mImageUri,null,selection,selectionArgs,Media.DATE_MODIFIED);
    				while (mCursor.moveToNext()) {
    					String path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media.DATA));
    					int duration= mCursor.getInt(mCursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
    					MusicFile musicFile=new MusicFile();
    					musicFile.setDir(path);
    					musicFile.setMusicDuration(duration);
    					musicFiles.add(musicFile);
    				}
    				mCursor.close();
    				// 通知Handler扫描图片完成
    				mHandler.sendEmptyMessage(MUSIC_SCARCH_FINISH);
    			}
    		}).start();
    	}
    }

    2.音乐文件对应实体类  MusicFile.java

    /**
     * 音乐文件对应实体类
     */
    public class MusicFile{
    	private String dir;//音乐绝对路径
    	private String name;//音乐名称
    	private int musicDuration;//音乐时长
    	
    	public String getDir() {
    		return dir;
    	}
    
    	public void setDir(String dir) {
    		this.dir = dir;
    		int lastIndexOf = this.dir.lastIndexOf("/");
    		this.name = this.dir.substring(lastIndexOf);
    	}
    	
    	public String getName() {
    		return name;
    	}
    
    	public int getMusicDuration() {
    		return musicDuration;
    	}
    
    	public void setMusicDuration(int musicDuration) {
    		this.musicDuration = musicDuration;
    	}
    }


    3.工具类,封装一些静态方法   Utils.java

    public class Utils {
    	/**
    	 * 判断文件是否是图片
    	 * @param fileName
    	 * @return
    	 */
    	public static boolean isImage(String fileName){
    		if (fileName.endsWith(".jpg")|| fileName.endsWith(".JPG")|| fileName.endsWith(".png")|| fileName.endsWith(".PNG")
    				|| fileName.endsWith(".jpeg")|| fileName.endsWith(".JPEG")|| fileName.endsWith(".gif")|| fileName.endsWith(".GIF"))
    			return true;
    		return false;
    	}
    	
    	/**
    	 * 根据资源ID得到字符串
    	 * @param context
    	 * @param resId
    	 * @return
    	 */
    	public static String getStringByResId(Context context,int resId){
    		return context.getString(resId);
    	}
    	
    	public static String getMusicDuration(int duration){
    		SimpleDateFormat sdf=new SimpleDateFormat("mm:ss");
    		return sdf.format(duration);
    	}
    }
    



    4.activity_select_music.xml    里面就一个ListView

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/list_music"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>

    5.ListView的Item布局文件   item_music_file.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <LinearLayout
            android:paddingTop="15dp"
        		android:paddingBottom="15dp"
            android:id="@+id/music_info"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal" >
    
            <ImageView
                android:id="@+id/iv_play_state"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:src="@drawable/button_music_normal" />
    
            <TextView
                android:id="@+id/music_folder_name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="4"
                android:gravity="left"
                android:maxLines="1"
                android:text="本地声音文件名称"
                android:textSize="16sp" />
    
            <TextView
                android:id="@+id/music_duration"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="9dp"
                android:layout_weight="1"
                android:gravity="right"
                android:text="0:00"
                android:textColor="#848484"
                android:textSize="14sp" />
        </LinearLayout>
        
        <RelativeLayout
            android:id="@+id/rl_music_capture"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/music_info"
            android:background="#1D1D1D"
            android:padding="9dp">
    
            <SeekBar
                android:id="@+id/sb_progress"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/txt_start_time"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="4dp"
                android:layout_marginRight="4dp"
                android:maxHeight="36dip"
                android:minHeight="36dip"
                android:paddingLeft="20dp"
                android:paddingRight="12dp"
                android:background="#1D1D1D"
                android:progressDrawable="@drawable/bg_bar"
                android:thumb="@drawable/icon_seekbar_pointer"
                android:thumbOffset="18dp" />
    
            <TextView
                android:id="@+id/txt_start_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentTop="true"
                android:layout_marginLeft="9dp"
                android:text="0:00"
                android:textColor="#AFAFAF"
                android:textSize="16sp" />
    
            <TextView
                android:id="@+id/txt_end_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:layout_marginRight="4dp"
                android:text="4:50"
                android:textColor="#AFAFAF"
                android:textSize="16sp" />
        </RelativeLayout>
    </RelativeLayout>


    效果图如下:



    以上就是所有的源码跟效果图,有需要的朋友可以参考一下。推荐下自己创建的android QQ群:202928390   欢迎大家的加入


    点击下载源码

  • 相关阅读:
    asp.net core 自定义401和异常显示内容(JWT认证、Cookie Base认证失败显示内容)
    asp.net core 微信APP支付(扫码支付,H5支付,公众号支付,app支付)之4
    asp.net core 支付宝支付( 电脑2.0)
    asp.net core 微信公众号支付(扫码支付,H5支付,公众号支付,app支付)之3
    asp.net core 微信获取用户openid
    asp.net core 微信H5支付(扫码支付,H5支付,公众号支付,app支付)之2
    asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1
    论BOM管理的若干重要问题
    BOM的编制与管理
    设计变更时,零部件的标识是变号还是升版?
  • 原文地址:https://www.cnblogs.com/yishaochu/p/5078624.html
Copyright © 2011-2022 走看看