Android小项目之音乐播放器简易版

来源:互联网 发布:sql修复工具 编辑:程序博客网 时间:2024/06/09 06:01

V1.0-最简单的一种,只有MediaPlay


activity.xml

 <Button        android:id="@+id/btn_play"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="播放" /><Button        android:id="@+id/btn_pause"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="播放" /> 

manifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

MainActivity.java

package com.xks.musicplayer;import android.media.MediaPlayer;import android.os.Bundle;import android.os.Environment;import android.support.v7.app.AppCompatActivity;import android.view.View;import java.io.IOException;public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private MediaPlayer mediaPlayer = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mediaPlayer = new MediaPlayer();        //这里通过getExternalStoragePublicDirectory方法获取到了sd卡中的公共路径中的Music目录,同理我们还可以获取其他的公共目录        String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath() + "/许巍 - 那一年.mp3";        try {            //这里设置了mediaPlayer要播放的资源所在路径            mediaPlayer.setDataSource(path);            //如果不准备就进行play会报state 0错误,如果多次准备会报state 1错误 这里mediaPlayer的使用流程请参照下图 不需要prepare操作的情况是当pause后重新start            mediaPlayer.prepare();        } catch (IOException e) {            e.printStackTrace();        }    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_play:                mediaPlayer.start();                break;            case R.id.btn_pause:                mediaPlayer.pause();                break;        }    }}

V2.0-加入服务和播放列表

总结:

  1. 因为在manifest.xml文件中忘记对服务进行注册导致出错
  2. 使用MediaPlayer特别需要了解下面的流程,否则容易出现state 0,1,8等错误
  3. 不要忘记权限,特别是如果手机是6.0我们还要动态权限
  4. 使用mediaPlayer类必须要对下图的使用流程有较深的理解
  5. 为什么会有prepareAsync呢?因为有些要播放的文件可能很大,所以需要进行异步准备,以免ANR(application not responding)
  6. 我们可以为mediaPlayer注册一个监听器setOnPreparedListener,在其中重写onPrepare方法,当监听到已经准备好了后就调用mediaPlayer.start()方法
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {    @Override    public void onPrepared(MediaPlayer mp) {        mp.start();        isPause = false;    }});

这里写图片描述


代码的目录结构

MyMusicAdapter>这是一个很简单的播放列表的适配器

public class MyMusicAdapter extends BaseAdapter {    @Override    public int getCount() {        return MyApp.musicBeanList == null ? 0 : MyApp.musicBeanList.size();    }    @Override    public MusicBean getItem(int position) {        return MyApp.musicBeanList.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder viewHolder;        MusicBean musicBean =  MyApp.musicBeanList.get(position);        if (convertView == null) {            convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_music, null);            viewHolder = new ViewHolder();            viewHolder.mTextView = (TextView) convertView.findViewById(R.id.tv_music);            viewHolder.mTextView.setText(musicBean.getMusicName());            convertView.setTag(viewHolder);        } else {            viewHolder = (ViewHolder) convertView.getTag();            viewHolder.mTextView.setText(musicBean.getMusicName());        }        return convertView;    }    class ViewHolder {        private TextView mTextView;    }}

MusicBean>歌曲实体类,存放了歌曲名称和路径以及getter/setter/toString方法

public class MusicBean {    private String musicName;    private String musicPath;    public MusicBean() {    }    public MusicBean(String musicName, String musicPath) {        this.musicName = musicName;        this.musicPath = musicPath;    }    public String getMusicName() {        return musicName;    }    public void setMusicName(String musicName) {        this.musicName = musicName;    }    public String getMusicPath() {        return musicPath;    }    public void setMusicPath(String musicPath) {        this.musicPath = musicPath;    }    @Override    public String toString() {        return "MusicBean{" +                "musicName='" + musicName + '\'' +                ", musicPath='" + musicPath + '\'' +                '}';    }}

MyApp extends Application 特别注意需要在manifest.xml文件中声明:
android:name=”MyApp”
里面存放的是歌曲集合,由于本类继承自application,因此歌曲集合是一个全局变量,只需要在服务中对目标文件夹进行遍历将以.mp3结尾的歌曲加入集合即可

public class MyApp extends Application {    //播放列表音乐集合,MusicBean实体类中着存放歌曲名称和歌曲所在目录    public static List<MusicBean> musicBeanList;    @Override    public void onCreate() {        super.onCreate();        musicBeanList = new ArrayList<MusicBean>();    }}

MusicService>音乐服务类,使用绑定服务的方式打开后再使用startService方法,使得播放器可以在用户打开activity的时候与服务进行交互,在用户关闭了activity的时候在onDestroy方法中解除绑定,使服务可以后台运行播放音乐

public class MusicService extends Service {    MediaPlayer mediaPlayer;//播放歌曲的类    private int currentPlaying = 0;//正在播放的歌曲    private static final String TAG = "MusicService";    public static boolean isPlaying = false;//是否处于播放状态    public static boolean isPause = false;//是否处于暂停状态    /**     * 服务Create,此时应当生成播放列表并初始化MediaPlay类     */    @Override    public void onCreate() {        super.onCreate();        if (mediaPlayer == null) {            mediaPlayer = new MediaPlayer();        }    }    @Override    public IBinder onBind(Intent intent) {        Log.e(TAG, "方法名>>onBind()");        final MyBinder myBinder = new MyBinder();        if (MyApp.musicBeanList.size() == 0) {            myBinder.createPlayList();            Log.e(TAG, "方法名>>onBind()" + MyApp.musicBeanList.toString());        }        return myBinder;    }    /**     * 服务与activity进行交互的方法     */    public class MyBinder extends Binder {        /**         * 播放指定位置的歌曲         *         * @param music         */        public void playMusic(MusicBean music, int position) {            try {                /*                 * Resets the MediaPlayer to its uninitialized state. After calling this method,                 * you will have to initialize it again by setting the data source and calling prepare().                 */                if (isPlaying&&isPause) {//播放状态但是被暂停了                    if (currentPlaying != position) {//正在播放的与点击的歌不是同一首                        setMusic(music);                    } else if (currentPlaying == position) {//是同一首歌                        mediaPlayer.start();//=>无需prepare,直接start就行                        isPause = false;                    }                }else{//没有播放                    setMusic(music);                }                currentPlaying = position;            } catch (IOException e) {                e.printStackTrace();            }        }        private void setMusic(MusicBean music) throws IOException {            mediaPlayer.reset();//reset后需要重新确定要播放的音乐所在路径            mediaPlayer.setDataSource(music.getMusicPath());            mediaPlayer.prepareAsync();            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {                @Override                public void onPrepared(MediaPlayer mp) {                    mp.start();                    isPause = false;                    isPlaying = true;                }            });        }        /**         * 暂停播放         */        public void pauseMusic() {            if (mediaPlayer.isPlaying()) {//正在播放时                mediaPlayer.pause();                isPlaying = true;                isPause = true;            }        }        /**         * 子线程中扫描歌曲>生成播放列表         * 遍历SD卡下的Music文件夹(mnt>shell>emulated>0>MUSIC),获取以.mp3结尾的文件并装入集合         */        public void createPlayList() {            new Thread() {                @Override                public void run() {                    MyApp.musicBeanList.clear();                    File musicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);                    File[] files = musicDirectory.listFiles();                    for (File file : files) {                        if (file.getName().endsWith(".mp3")) {                            MusicBean musicBean = new MusicBean();                            musicBean.setMusicName(file.getName());                            musicBean.setMusicPath(file.getAbsolutePath());                            MyApp.musicBeanList.add(musicBean);                        }                    }                }            }.start();        }    }    @Override    public void onDestroy() {        //在服务中的onDestroy方法中对mediaPlayer资源进行释放        mediaPlayer.release();        //将mediaPlayer赋空便于垃圾回收器进行回收        mediaPlayer = null;        super.onDestroy();    }}

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener ,AdapterView.OnItemClickListener {    private static final String TAG = "MainActivity";    private Button playButton;    private Button pauseButton;    private ListView mListView;    private MyMusicAdapter myMusicAdapter;    private MusicService.MyBinder myBinder;//Binder对象    private MyServiceConnected myServiceConnected;    private int currentPlaying = 0;//正在播放的是第几首歌    private Button mRefreshPlayList;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        playButton = (Button) findViewById(R.id.btn_play);        pauseButton = (Button) findViewById(R.id.btn_pause);        mRefreshPlayList = (Button) findViewById(R.id.btn_flush_playlist);        mListView = (ListView) findViewById(R.id.lv_listview);        //通过绑定的方式开启服务,该方式可以使activity与服务进行通信        Intent intent = new Intent(this,MusicService.class);        myServiceConnected = new MyServiceConnected();        bindService(intent, myServiceConnected,BIND_AUTO_CREATE);        startService(intent);        playButton.setOnClickListener(this);        pauseButton.setOnClickListener(this);        mRefreshPlayList.setOnClickListener(this);        mListView.setOnItemClickListener(this);    }    /**     * 退出activity时要解除与服务的绑定     */    @Override    protected void onDestroy() {        unbindService(myServiceConnected);        super.onDestroy();    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_play://播放音乐                Log.d(TAG, "myBinder ==null? " + (myBinder == null));                myBinder.playMusic(MyApp.musicBeanList.get(currentPlaying),currentPlaying);                break;            case R.id.btn_pause://暂停音乐                myBinder.pauseMusic();                break;            case R.id.btn_flush_playlist:                myBinder.createPlayList();                myMusicAdapter.notifyDataSetChanged();                break;        }    }    private class MyServiceConnected implements ServiceConnection{        /**         * 绑定服务成功回调         * @param componentName         * @param service         */        @Override        public void onServiceConnected(ComponentName componentName, IBinder service) {            Log.e(TAG, "类名>>MainActivity>>方法名>>onServiceConnected()");            myBinder = (MusicService.MyBinder) service;            myMusicAdapter = new MyMusicAdapter();            mListView.setAdapter(myMusicAdapter);        }        /**         * 服务意外挂掉回调         * @param name         */        @Override        public void onServiceDisconnected(ComponentName name) {        }    }    @Override    public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {        MusicBean musicBean = myMusicAdapter.getItem(position);        currentPlaying = position;        Log.e(TAG, "类名>>MainActivity>>方法名>>onItemClick()"+musicBean.getMusicName());        myBinder.playMusic(musicBean,position);    }}

activity_main.xml

<Button        android:id="@+id/btn_play"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="播放" />    <Button        android:id="@+id/btn_pause"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_toRightOf="@id/btn_play"        android:text="暂停" />    <Button        android:id="@+id/btn_flush_playlist"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="刷新播放列表"        android:layout_toRightOf="@+id/btn_pause"/>    <ListView        android:id="@+id/lv_listview"        android:scrollbars="none"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_below="@id/btn_play" />

item_music

 <TextView        android:id="@+id/tv_music"        android:textSize="25sp"        android:layout_gravity="center"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:paddingBottom="5dp" />

GitHub 源代码下载:https://github.com/a1265137718/AndroidProjectRepository.git

0 0
原创粉丝点击