音乐播放器,注意静态常量的使用命名要有明确具体的含义(查看API,若想获得音乐本身自带的歌手名以及图片等信息,可查看MediaMetadataRetrieve来获得详细信息)

来源:互联网 发布:acii转换为hex单片机 编辑:程序博客网 时间:2024/04/29 14:38

  • 另外注意Log的使用
  • 注意权限的添加
  • 音乐播放器带有缓存功能
    • 主程序
    • 音乐部分程序
      • MusicService服务程序
      • song程序里面含有未开发部分
      • SongAdapter适配器程序
  • 布局文件
    • 主布局文件
    • 单条Song的布局文件
  • checkbox的按压文件
  • button的按压文件
    • 从MP3中获取图片需要用到一个jar包可在云盘中找到不过这个也是需要传绝对路径

另外注意Log的使用

注意权限的添加

读取存储卡的权限

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

音乐播放器带有缓存功能

主程序

package com.test.myplayer;import android.support.v7.app.ActionBarActivity;import android.util.Log;import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.List;import com.test.service.MusicService;import com.test.song.Song;import com.test.song.SongAdapter;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.SharedPreferences;import android.media.MediaPlayer;import android.media.MediaPlayer.OnPreparedListener;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.Button;import android.widget.CheckBox;import android.widget.CompoundButton;import android.widget.CompoundButton.OnCheckedChangeListener;import android.widget.ImageButton;import android.widget.ListView;import android.widget.SeekBar;import android.widget.TextView;public class MainActivity extends Activity implements OnClickListener {    "静态常量是为了避免使用时拼写错误,另外因为有具体的名,所以使用时容易辨别它的作用。"    public final static String ACTION = "com.test.myplayer";    public final static int TYPE_PLAYER = 1;    public final static int TYPE_PAUSE = 2;    public final static int TYPE_SEEKTO = 3;    public final static int TYPE_CHECKBOX_CHECKED = 4;    // public final static int TYPE_PRE=4;    // public final static int TYPE_NEXT=5;    public final static String PLAY_TYPE_FLAG = "12";    private TextView mAllTime;//获得歌曲的总时长    private TextView mCurrentTime;//歌曲目前播放到的时长    private ImageButton mButtonPrevious;//上一首    private ImageButton mButtonNext;//下一首    private Boolean mIsChecked = false;//默认checkbox的状态值    private SeekBar seekBar1;//歌曲进度条    private CheckBox mCheckBoxPlayer;//checkbox的实例    private List<Song> mListSong;//Song的集合    private LayoutInflater mInflater;    private SongAdapter mAdapter;//song的适配器    private ListView listView;//listView用来填充song    private List<File> fileMp3 = new ArrayList<File>();//辅助的集合用来村完整的歌曲名    private String songPath;//song的路径    private int mSongNum;//当前播放的song在集合中的位置    private MusicBroadcast mBroadcastReceiver;//广播接收者    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //给所用控件初始化        mAllTime = (TextView) findViewById(R.id.all_time);        mCurrentTime = (TextView) findViewById(R.id.current_time);        mButtonPrevious = (ImageButton) findViewById(R.id.previous_button);        mButtonNext = (ImageButton) findViewById(R.id.next_button);        listView = (ListView) findViewById(R.id.list_song);        mCheckBoxPlayer = (CheckBox) findViewById(R.id.play_checkbox);        seekBar1 = (SeekBar) findViewById(R.id.seekBar1);        //添加点击事件        mButtonPrevious.setOnClickListener(this);        mButtonNext.setOnClickListener(this);        mBroadcastReceiver = new MusicBroadcast();        //注册广播接收者        IntentFilter filter = new IntentFilter();        filter.addAction(ACTION);        registerReceiver(mBroadcastReceiver, filter);        //集合添加数据一定要在前面。        mListSong = new ArrayList<Song>();        mInflater = getLayoutInflater();        //此时获得是一进入文件管理时的路径        File customFiles = Environment.getExternalStorageDirectory();        //然后通过新建文件则要查找的文件夹        File file = new File(customFiles, "/netease/cloudmusic/Music");        //下面屏蔽的是直接去存储卡自带的Music文件下查找        // File file =        // Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);        File[] files = file.listFiles();        for (File innerfile : files) {            String name = innerfile.getName();            int index = name.lastIndexOf(".");            String last = name.substring(index, name.length());// index包含最后一位判断最后的结尾方式            //获取其中的全部的mp3文件            if (last.equals(".mp3") || last.equals(".wav")) {                fileMp3.add(innerfile);                String songName = name.substring(0, index);                Log.d("lala", songName);                Song song = new Song(songName);                mListSong.add(song);            }        }        //给适配器传入值        mAdapter = new SongAdapter(mInflater, mListSong);        listView.setAdapter(mAdapter);        //给每条listView添加点击事件        listView.setOnItemClickListener(new OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                //通过position来判断当前点击的是哪一条list                File sigleSong = fileMp3.get(position);                //获得这是该条在集合中的位置,方便之后播放前一首或后一首时有个参照。                mSongNum = position;                Log.d("nihao", "" + sigleSong.getAbsolutePath());                songPath = sigleSong.getAbsolutePath();                //启动服务播放歌曲                Intent intent = new Intent(getApplicationContext(), MusicService.class);                //将所需的数据通过intent传递。                intent.putExtra("musicpath", songPath);                intent.putExtra(PLAY_TYPE_FLAG, TYPE_PLAYER);                mCheckBoxPlayer.setChecked(true);                startService(intent);            }        });        mButtonPrevious.setOnClickListener(this);        //滑动条添加拖动事件,一共有三个事件使用时注意查看API        seekBar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {                // fromUser判断是用户改变的滑块的值                if (fromUser == true) {                    Intent intent = new Intent(getApplicationContext(), MusicService.class);                    intent.putExtra(PLAY_TYPE_FLAG, TYPE_SEEKTO);                    intent.putExtra("SeekBar", progress);                    startService(intent);                }            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {                // TODO Auto-generated method stub            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {                // TODO Auto-generated method stub            }        });        //CheckBox的选择事件        mCheckBoxPlayer.setOnCheckedChangeListener(new OnCheckedChangeListener() {            @Override            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {                mIsChecked = isChecked;                //isChecked是此时的状态,通过状态判断来做出相应的动作。                if (mIsChecked) {                    SharedPreferences sharedPreferences = getSharedPreferences(MusicService.FILE_NAME, MODE_PRIVATE);                    songPath = sharedPreferences.getString(MusicService.PATH_PAUSE, "0");                    int psuseTime = Integer.parseInt(sharedPreferences.getString(MusicService.PAUSE_NOTE, "0"));                    Intent intent = new Intent(getApplicationContext(), MusicService.class);                    intent.putExtra(PLAY_TYPE_FLAG, TYPE_CHECKBOX_CHECKED);                    intent.putExtra("musicPausePath", songPath);                    intent.putExtra(MusicService.PAUSE_NOTE, psuseTime);                    startService(intent);                } else {                    Intent intent = new Intent(getApplicationContext(), MusicService.class);                    intent.putExtra(PLAY_TYPE_FLAG, TYPE_PAUSE);                    intent.putExtra("musicpath", songPath);                    startService(intent);                }            }        });    }    @Override    public void onClick(View v) {        switch (v.getId()) {        case R.id.previous_button:            mSongNum -= 1;            //都是通过intent发送给后台的服务            File sigleSongPre = fileMp3.get(mSongNum);            songPath = sigleSongPre.getAbsolutePath();            Intent intent = new Intent(getApplicationContext(), MusicService.class);            intent.putExtra("musicpath", songPath);            //通过传入不同的类型方便后台服务根据类型来区分            intent.putExtra(PLAY_TYPE_FLAG, TYPE_PLAYER);            //别忘了启动服务            startService(intent);            break;        case R.id.next_button:            mSongNum += 1;            File sigleSongNext = fileMp3.get(mSongNum);            songPath = sigleSongNext.getAbsolutePath();            Intent intentNext = new Intent(getApplicationContext(), MusicService.class);            intentNext.putExtra("musicpath", songPath);            intentNext.putExtra(PLAY_TYPE_FLAG, TYPE_PLAYER);            startService(intentNext);            break;        }    }    @Override    protected void onDestroy() {        super.onDestroy();        //销毁活动时,注意给broadcast取消注册。        unregisterReceiver(mBroadcastReceiver);    }    /**     *在类的内部创建Broadcast来接收服务传递过来的信息     */    class MusicBroadcast extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            //也是通过类型的判断来区分后台服务传递过来的信息            int type = intent.getIntExtra("type", 0);            switch (type) {            case 1:                int timeall = intent.getIntExtra("time", 0);                seekBar1.setMax(timeall);                int fen = (timeall / 1000) / 60;                int miao = (timeall / 1000) % 60;                String time1 = fen + ":" + miao;                mAllTime.setText(time1);                break;            case 2:                int timecurrent = intent.getIntExtra("time", 0);                seekBar1.setProgress(timecurrent);                int fen2 = (timecurrent / 1000) / 60;                int miao2 = (timecurrent / 1000) % 60;                String time2 = fen2 + ":" + miao2;                mCurrentTime.setText(time2);                break;            default:                break;            }        }    }}

音乐部分程序

MusicService服务程序

package com.test.service;import java.io.IOException;import com.test.myplayer.MainActivity;import android.app.Service;import android.content.Intent;import android.content.SharedPreferences;import android.media.MediaPlayer;import android.media.MediaPlayer.OnPreparedListener;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.util.Log;public class MusicService extends Service {    private MediaPlayer player;    private String songPath;    public final static String FILE_NAME = "pauseNotes";    public final static String PATH_PAUSE = "PATH";    public final static String PAUSE_NOTE = "PAUSE";//暂停时存入缓存的时间标志。    public final static int ALL_TIME = 1;    public final static int CURRENT_TIME = 2;    @Override    public IBinder onBind(Intent intent) {        // TODO Auto-generated method stub        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d("123", 156 + "");        得到intent传递的值        int playType = intent.getIntExtra(MainActivity.PLAY_TYPE_FLAG, 0);        switch (playType) {        case MainActivity.TYPE_PLAYER:            if (player == null) {                player = new MediaPlayer();            }            player.reset();            //得到文件的路径            songPath = intent.getStringExtra("musicpath");            try {                Log.d("123", songPath);                player.setDataSource(songPath);                player.prepare();                int time = player.getDuration();                player.start();                Intent intent1 = new Intent(MainActivity.ACTION);                intent1.putExtra("type", ALL_TIME);                intent1.putExtra("time", time);                //发送广播                sendBroadcast(intent1);                //开启线程                MyMusicThread thread = new MyMusicThread();                thread.start();                // player.setOnPreparedListener(new OnPreparedListener() {                //                // @Override                // public void onPrepared(MediaPlayer mp) {                // if (mp.isPlaying()) {                //                // } else {                //                // mp.start();                // int time = player.getDuration();                // Intent intent = new Intent();                // intent.putExtra("type", ALL_TIME);                // intent.putExtra("time", time);                // sendBroadcast(intent);                // MyMusicThread thread = new MyMusicThread();                // thread.start();                // }                //                // }                // });            } catch (IllegalArgumentException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (SecurityException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (IllegalStateException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            break;        case MainActivity.TYPE_PAUSE:            //得到此时的播放进度,然后暂停,并将进度存入缓存            int pausePosition = player.getCurrentPosition();            player.pause();            SharedPreferences sharedPreferences = getSharedPreferences(FILE_NAME, MODE_PRIVATE);            SharedPreferences.Editor editor = sharedPreferences.edit();            editor.putString(PAUSE_NOTE, "" + pausePosition);            editor.putString(PATH_PAUSE, songPath);            editor.commit();            break;        case MainActivity.TYPE_SEEKTO:            //拖动seekbar的响应事件            int progress = intent.getIntExtra("SeekBar", 0);            if (player != null) {                player.seekTo(progress);            }            break;        case MainActivity.TYPE_CHECKBOX_CHECKED:            if (player == null) {                    //防止文件为空                    player = new MediaPlayer();                if (!player.isPlaying()) {                    songPath = intent.getStringExtra("musicPausePath");// 默认文件中所存储的音乐                    int pauseTime = intent.getIntExtra(PAUSE_NOTE, 0);// 初始时要seekto到的时间。                    Log.d("lalalla", songPath+pauseTime);                    try {                        player.setDataSource(songPath);                        player.prepare();                    } catch (IllegalArgumentException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    } catch (SecurityException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    } catch (IllegalStateException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    } catch (IOException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                    int time = player.getDuration();                    player.start();                    player.seekTo(pauseTime);                    Intent intent1 = new Intent(MainActivity.ACTION);                    intent1.putExtra("type", ALL_TIME);                    intent1.putExtra("time", time);                    sendBroadcast(intent1);                    MyMusicThread thread = new MyMusicThread();                    thread.start();                }            }            break;        default:            break;        }        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        super.onDestroy();    }    /**     *创建一个线程不断调整时间然后发送广播给主程序。     */    class MyMusicThread extends Thread {        @Override        public void run() {            while (player.isPlaying()) {                int time = player.getCurrentPosition();                Intent intent = new Intent(MainActivity.ACTION);                intent.putExtra("type", CURRENT_TIME);                intent.putExtra("time", time);                sendBroadcast(intent);                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }}

song程序,里面含有未开发部分

package com.test.song;public class Song {    private String name;    private String author;    private int Image;    public String getAuthor() {        return author;    }    public void setAuthor(String author) {        this.author = author;    }    public int getImage() {        return Image;    }    public void setImage(int image) {        Image = image;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Song(String name) {        this.name = name;    }}

SongAdapter适配器程序

package com.test.song;import java.io.File;import java.util.List;import com.test.myplayer.R;import android.annotation.TargetApi;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.media.MediaMetadata;import android.media.MediaMetadataRetriever;import android.os.Build;import android.os.Environment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)public class SongAdapter extends BaseAdapter{    private LayoutInflater mInflater;    private List<Song> mListSong;    public SongAdapter(LayoutInflater mInflater, List<Song> mListSong) {        this.mInflater = mInflater;        this.mListSong = mListSong;    }    @Override    public int getCount() {        return mListSong.size();    }    @Override    public Object getItem(int position) {        return position;    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder viewHolder=null;        if(convertView==null){            convertView=mInflater.inflate(R.layout.list_song, null);            viewHolder=new ViewHolder();//          viewHolder.author=(TextView) convertView.findViewById(R.id.author);//          viewHolder.image=(ImageView) convertView.findViewById(R.id.image);            viewHolder.name=(TextView) convertView.findViewById(R.id.song_name);            convertView.setTag(viewHolder);        }else{            viewHolder=(ViewHolder) convertView.getTag();        }        Song song=mListSong.get(position);        /**         * 当传入完整路径时使用该部分,通过路径使用MediaMetadataRetriever         */         "这里可以获得歌手名,但是同样需要传入的是完整的路径名"//      File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);//      File[] files = file.listFiles();//  //      MediaMetadataRetriever mediaRetraiver=new MediaMetadataRetriever();//      mediaRetraiver.setDataSource(files[0].getAbsolutePath());//      String author=mediaRetraiver.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);//      if(author!=null){//          viewHolder.author.setText(author);//          //      }else{//          viewHolder.author.setText("<未知>");//      }        viewHolder.name.setText(song.getName());//      byte[] image=mediaRetraiver.getEmbeddedPicture();"这些屏蔽程序可以画一个图片添加到单条布局中,但是需要传入完整的文件路径"//      if(image!=null){//          Bitmap bitmap=BitmapFactory.decodeByteArray(image, 0, image.length);//          viewHolder.image.setImageBitmap(bitmap);//      }else{//          viewHolder.image.setImageResource(R.drawable.ic_launcher);//      }        return convertView;    }    class ViewHolder{        ImageView image;        TextView author;        TextView name;    }}

布局文件

主布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@drawable/playpage_background"    android:orientation="vertical" >    <ListView        android:id="@+id/list_song"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        android:cacheColorHint="#ffffffff"        android:divider="#55ff0000" >    </ListView>    <LinearLayout         android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="horizontal"        android:gravity="center">    <TextView         android:id="@+id/all_time"        android:layout_gravity="center"        android:layout_width="wrap_content"        android:layout_height="wrap_content"          android:textSize="15sp"        android:text="00:00"/>    <SeekBar        android:id="@+id/seekBar1"        android:layout_width="254dp"        android:layout_height="wrap_content"        android:layout_gravity="bottom"        android:layout_marginBottom="10dp" />    <TextView         android:id="@+id/current_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textSize="15sp"        android:text="00:00"/></LinearLayout>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="50dp"        android:gravity="center"        android:orientation="horizontal" >        <ImageButton            android:id="@+id/previous_button"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginRight="20dp"            android:scaleX="2"            android:scaleY="2"            android:background="@drawable/previousbackground" />        <CheckBox            android:id="@+id/play_checkbox"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:scaleX="2"            android:scaleY="2"            android:background="@drawable/playback"            android:button="@null" />        <ImageButton            android:id="@+id/next_button"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="20dp"            android:scaleX="2"            android:scaleY="2"            android:background="@drawable/nextbackground" />    </LinearLayout></LinearLayout>

单条Song的布局文件

<?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:gravity="center" >    <ImageView         android:id="@+id/image"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        />    <TextView         android:id="@+id/song_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textSize="20sp"        android:text="ni"/>    <TextView        android:id="@+id/author"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textSize="20sp"        /></LinearLayout>

checkbox的按压文件

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android" >       <item android:drawable="@drawable/desk_pause" android:state_checked="true"/>    <!--没有加状态的放在后面-->    <item android:drawable="@drawable/desk_play"/></selector>

button的按压文件

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android" >    <item android:drawable="@drawable/desk_next_prs" android:state_pressed="true"/>    <!--没有加状态的放在后面-->    <item android:drawable="@drawable/desk_next"/></selector>

从MP3中获取图片需要用到一个jar包,可在云盘中找到,不过这个也是需要传绝对路径。

这里写图片描述

0 0
原创粉丝点击