音乐播放器,注意静态常量的使用命名要有明确具体的含义(查看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
- 音乐播放器,注意静态常量的使用命名要有明确具体的含义(查看API,若想获得音乐本身自带的歌手名以及图片等信息,可查看MediaMetadataRetrieve来获得详细信息)
- 使用android模拟器自带的音乐播放器播放音乐
- 获得系统的音乐
- 获得百度音乐隐蔽API的源代码
- 音乐播放器-使用jaudiotagger获得音频元信息
- Android 超简单音乐播放器(九)搜索网络歌曲,获得热门榜单(GridView)(易源api的使用)(JSON的解析)(刷新)
- android自带音乐播放器删除音乐失败的问题
- android音乐播放器-------使用android系统自带的数据库
- 带进度条的播放音乐
- 带服务的音乐播放器
- 扫描IPHONE本地音乐文件,获得音乐名,歌手名代码示例
- 使用Audio API设计绚丽的HTML5音乐播放器
- 关于获得手机里的本地音乐
- 关于获得手机里的本地音乐
- Android AIDL技术实战项目-音乐播放器(二)-使用retrofit完成音乐API的封装
- 模仿音乐播放器带进度的播放暂停按钮
- Android带播放进度条的音乐播放器
- Adnroid调用自身的播放器来播放音乐
- PIC知识点汇总
- [MFC]DlgDemo2程序:非模态对话框的基本应用
- C语言运算符
- LeetCode OJ2 Add Two Numbers 小结
- RTAI installation for Ubuntu 14.04
- 音乐播放器,注意静态常量的使用命名要有明确具体的含义(查看API,若想获得音乐本身自带的歌手名以及图片等信息,可查看MediaMetadataRetrieve来获得详细信息)
- MySQL体系结构以及各种文件类型学习汇总
- 黑马程序员--文件数据IO操作
- 本地socket 通讯说明
- 收藏
- Linux 的 curl命令的使用
- Jackson学习笔记
- AngularJS filter
- java-基础巩固 3