平台:Android studio
APK:http://fir.im/apps/56ea5187e75e2d69af000042
本地的音乐播放器,主要功能就是可以播放音乐,能够读取本地的音乐,并显示出来,播放,暂停,上一首,下一首,进度条可以拖拽播放,添加了前台service,看一下实现
首先我是先做了一个大概的布局,样子先出来,需要其他的空间后期再添加,毕竟一开始不可能想的太详细,看一下主布局文件,就是一个listView 和几个ImageButton,又自己添加了一个title,有个可以进度条,需要可以拖动,使用了seekBar
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" tools:context="com.cl.android.music.MusicActivity" android:background="@color/background" android:id="@+id/contentmusic" > <include layout="@layout/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:id="@+id/include" /> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/musicListView" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@+id/include" android:layout_above="@+id/seekBar" /> <SeekBar android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/seekBar" android:layout_above="@+id/musicinfo" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <TextView android:layout_width="match_parent" android:layout_height="25dp" android:gravity="center" android:id="@+id/musicinfo" android:layout_above="@+id/previous" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <ImageView android:id="@+id/previous" android:layout_width="50dp" android:layout_height="50dp" android:background="@drawable/previous" android:onClick="previous" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <ImageView android:id="@+id/play_pause" android:layout_width="50dp" android:layout_height="50dp" android:background="@drawable/play" android:onClick="play_pause" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" /> <ImageView android:id="@+id/next" android:layout_width="50dp" android:layout_height="50dp" android:background="@drawable/next" android:onClick="next" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <!--<ImageButton android:id="@+id/previous" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/previous" android:onClick="previous" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <ImageButton android:id="@+id/play_pause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/play" android:onClick="play_pause" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" /> <ImageButton android:id="@+id/next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/next" android:onClick="next" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" />--> </RelativeLayout>每个音乐文件显示时的样式
<?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="match_parent"> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:id="@+id/video_imageView" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/video_title" android:text="@string/music_title" android:layout_alignTop="@+id/video_size" android:layout_alignLeft="@+id/video_singer" android:layout_alignStart="@+id/video_singer" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/video_singer" android:text="@string/music_singer" android:layout_marginLeft="20dp" android:layout_marginStart="20dp" android:layout_alignBaseline="@+id/video_duration" android:layout_alignBottom="@+id/video_duration" android:layout_toRightOf="@+id/video_imageView" android:layout_toEndOf="@+id/video_imageView" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/video_size" android:text="@string/music_size" android:layout_above="@+id/video_duration" android:layout_alignLeft="@+id/video_duration" android:layout_alignStart="@+id/video_duration" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/video_duration" android:text="@string/music_duration" android:layout_marginRight="75dp" android:layout_marginEnd="75dp" android:layout_alignBottom="@+id/video_imageView" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_marginBottom="15dp" /> </RelativeLayout>以及最上面的那个title
<?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="match_parent" android:background="@color/toolbarbackground" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp" android:text="@string/app_name" android:id="@+id/textView" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <ImageView android:id="@+id/click_share" android:onClick="clickShare" android:layout_width="20dp" android:layout_height="wrap_content" android:src="@drawable/share" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_marginRight="29dp" android:layout_marginEnd="29dp" /> </RelativeLayout>大概的布局出来后,就可以在填写逻辑代码了,思路肯定是先找到本地的音乐文件再显示出来了,本来思路是想 扫描SD卡获取本地文件,找出MP3文件,这样也是可以的,但是 Android系统会在SD卡有更新的时候自动将SD卡文件分类(视频/音频/图片...),并存入SQLite数据库,就保存在媒体存储器里面(com.android.providers.media),而我们要做的只是像正常读取数据库一样去读数据库的信息就好了,所以直接上代码,代码里都有注释
当前需要先加权限,src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
/*加载媒体库里的音频*/ public ArrayList<MusicMedia> scanAllAudioFiles(){ //生成动态数组,并且转载数据 ArrayList<MusicMedia> mylist = new ArrayList<MusicMedia>(); /*查询媒体数据库 参数分别为(路径,要查询的列名,条件语句,条件参数,排序) 视频:MediaStore.Video.Media.EXTERNAL_CONTENT_URI 图片;MediaStore.Images.Media.EXTERNAL_CONTENT_URI */ Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); //遍历媒体数据库 if(cursor.moveToFirst()){ while (!cursor.isAfterLast()) { //歌曲编号 int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)); //歌曲标题 String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); //歌曲的专辑名:MediaStore.Audio.Media.ALBUM String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)); int albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)); //歌曲的歌手名: MediaStore.Audio.Media.ARTIST String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)); //歌曲文件的路径 :MediaStore.Audio.Media.DATA String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); //歌曲的总播放时长 :MediaStore.Audio.Media.DURATION int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)); //歌曲文件的大小 :MediaStore.Audio.Media.SIZE Long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)); if (size >1024*800){//大于800K MusicMedia musicMedia = new MusicMedia(); musicMedia.setId(id); musicMedia.setArtist(artist); musicMedia.setSize(size); musicMedia.setTitle(tilte); musicMedia.setTime(duration); musicMedia.setUrl(url); musicMedia.setAlbum(album); musicMedia.setAlbumId(albumId); mylist.add(musicMedia); } cursor.moveToNext(); } } return mylist; }获取到之后我需要显示在list里,需要ArryList<Map<Object,object>>格式的数据,我上面是存储的一个对象,因为后面我需要单个音乐文件的信息,如果不需要单个文件信息可以在这里直接返回这种格式的数据,listView显示数据
musicList = scanAllAudioFiles(); //这里其实可以直接在扫描时返回 ArrayList<Map<String, Object>>() listems = new ArrayList<Map<String, Object>>(); for (Iterator iterator = musicList.iterator(); iterator.hasNext();) { Map<String, Object> map = new HashMap<String, Object>(); MusicMedia mp3Info = (MusicMedia) iterator.next(); // map.put("id",mp3Info.getId()); map.put("title", mp3Info.getTitle()); map.put("artist", mp3Info.getArtist()); map.put("album", mp3Info.getAlbum()); // map.put("albumid", mp3Info.getAlbumId()); map.put("duration", mp3Info.getTime()); map.put("size", mp3Info.getSize()); map.put("url", mp3Info.getUrl()); map.put("bitmap", R.drawable.musicfile); listems.add(map); } /*SimpleAdapter的参数说明 * 第一个参数 表示访问整个android应用程序接口,基本上所有的组件都需要 * 第二个参数表示生成一个Map(String ,Object)列表选项 * 第三个参数表示界面布局的id 表示该文件作为列表项的组件 * 第四个参数表示该Map对象的哪些key对应value来生成列表项 * 第五个参数表示来填充的组件 Map对象key对应的资源一依次填充组件 顺序有对应关系 * 注意的是map对象可以key可以找不到 但组件的必须要有资源填充 因为 找不到key也会返回null 其实就相当于给了一个null资源 * 下面的程序中如果 new String[] { "name", "head", "desc","name" } new int[] {R.id.name,R.id.head,R.id.desc,R.id.head} * 这个head的组件会被name资源覆盖 * */ SimpleAdapter mSimpleAdapter = new SimpleAdapter( this, listems, R.layout.music_item, new String[] {"bitmap","title","artist", "size","duration"}, new int[] {R.id.video_imageView,R.id.video_title,R.id.video_singer,R.id.video_size,R.id.video_duration} ); //listview里加载数据 musicListView.setAdapter(mSimpleAdapter);现在音乐列表显示在listView里了,可以点击,可以上下滑动,但是怎么实现点击播放呢,使用MediaPler,这是Android系统自带的播放器,这里给出其常用的方法的中文解释,其实大可以直接看英文API嘛
MediaPlayer 常用方法介绍 方法:create(Context context, Uri uri) 解释:静态方法,通过Uri创建一个多媒体播放器。 方法:create(Context context, int resid) 解释:静态方法,通过资源ID创建一个多媒体播放器 方法:create(Context context, Uri uri, SurfaceHolder holder) 解释:静态方法,通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器 方法: getCurrentPosition() 解释:返回 Int, 得到当前播放位置 方法: getDuration() 解释:返回 Int,得到文件的时间 方法:getVideoHeight() 解释:返回 Int ,得到视频的高度 方法:getVideoWidth() 解释:返回 Int,得到视频的宽度 方法:isLooping() 解释:返回 boolean ,是否循环播放 方法:isPlaying() 解释:返回 boolean,是否正在播放 方法:pause() 解释:无返回值 ,暂停 方法:prepare() 解释:无返回值,准备同步 方法:prepareAsync() 解释:无返回值,准备异步 方法:release() 解释:无返回值,释放 MediaPlayer 对象 方法:reset() 解释:无返回值,重置 MediaPlayer 对象 方法:seekTo(int msec) 解释:无返回值,指定播放的位置(以毫秒为单位的时间) 方法:setAudioStreamType(int streamtype) 解释:无返回值,指定流媒体的类型 方法:setDataSource(String path) 解释:无返回值,设置多媒体数据来源【根据 路径】 方法:setDataSource(FileDescriptor fd, long offset, long length) 解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】 方法:setDataSource(FileDescriptor fd) 解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】 方法:setDataSource(Context context, Uri uri) 解释:无返回值,设置多媒体数据来源【根据 Uri】 方法:setDisplay(SurfaceHolder sh) 解释:无返回值,设置用 SurfaceHolder 来显示多媒体 方法:setLooping(boolean looping) 解释:无返回值,设置是否循环播放 事件:setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) 解释:监听事件,网络流媒体的缓冲监听 事件:setOnCompletionListener(MediaPlayer.OnCompletionListener listener) 解释:监听事件,网络流媒体播放结束监听 事件:setOnErrorListener(MediaPlayer.OnErrorListener listener) 解释:监听事件,设置错误信息监听 事件:setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) 解释:监听事件,视频尺寸监听 方法:setScreenOnWhilePlaying(boolean screenOn) 解释:无返回值,设置是否使用 SurfaceHolder 显示 方法:setVolume(float leftVolume, float rightVolume) 解释:无返回值,设置音量 方法:start() 解释:无返回值,开始播放 方法:stop() 解释:无返回值,停止播放也就是说,使用mediaplayer需要传一个地址过去,这些信息在刚读取音频的方法里都有,直接使用就好了,使用一个service播放,新建一个service,不考虑其他,启动一个隐式的service,需要做一些修改,传一个地址过去先播放起来
在listview上添加监听器,怎么知道点击的音乐的地址,哈哈,有个position,可以定位到musiclist里具体的对象
musicListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //点击播放音乐,不过需要判断一下当前是否有音乐在播放,需要关闭正在播放的 //position 可以获取到点击的是哪一个,去 musicList 里寻找播放 currentposition = position; player(currentposition); } });
<service android:name=".MusicPlayerService" android:enabled="true" android:exported="true"> <intent-filter > <action android:name="player"></action> </intent-filter> </service>启动service
intent.setAction("player"); intent.setPackage(getPackageName()); intent.putExtra("url", musicList.get(position).getUrl()); startService(intent);再看看service端
@Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand......3"); // /storage/emulated/0/Music/Download/Selena Gomez - Revival/Hands to Myself.mp3 if(intent != null){ url = intent.getStringExtra("url"); mediaPlayer.setDataSource(url); mediaPlayer.setLooping(true);//单曲循环 mediaPlayer.prepare(); mediaPlayer.start(); } return super.onStartCommand(intent, flags, startId); }这样就可以直接播放啦,虽然现在只能播放,但是毕竟可以播放了,下面继续播放控制部分逻辑
进度条怎么显示当前的播放进度,我一开始的想法是service使用静态的变量,activity里也是使用静态的变量,然后开一个线程,1s更新一次状态,在service里直接修改seekbar,我就直接上代码了
public class MusicPlayerService extends Service implements Runnable { private static final String TAG = "MusicPlayerService"; private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台service public static MediaPlayer mediaPlayer = null; private String url = null; private String MSG = null; private static int curposition;//第几首音乐 private musicBinder musicbinder = null; private int currentPosition = 0;// 设置默认进度条当前位置 public MusicPlayerService() { Log.i(TAG,"MusicPlayerService......1"); musicbinder = new musicBinder(); } //通过bind 返回一个IBinder对象,然后改对象调用里面的方法实现参数的传递 @Override public IBinder onBind(Intent intent) { Log.i(TAG,"onBind......"); return null; } @Override public void onCreate() { Log.i(TAG, "onCreate......2"); super.onCreate(); if (mediaPlayer == null) { /* mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer = null;*/ mediaPlayer = new MediaPlayer(); } // 监听播放是否完成 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { //我目前也不知道该干嘛 } }); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand......3"); // /storage/emulated/0/Music/Download/Selena Gomez - Revival/Hands to Myself.mp3 if(intent != null){ MSG = intent.getStringExtra("MSG"); if(MSG.equals("0")){ url = intent.getStringExtra("url"); Log.i(TAG, url + "......." + Thread.currentThread().getName()); palyer(); }else if(MSG.equals("1")){ mediaPlayer.pause(); }else if(MSG.equals("2")){ mediaPlayer.start(); } } return super.onStartCommand(intent, flags, startId); } private void palyer() { Log.i(TAG,"palyer......"); //如果正在播放,先停止再播放新的 /* if(mediaPlayer.isPlaying()){ Log.i(TAG,"palyer......running...."); // 暂停 mediaPlayer.pause(); mediaPlayer.reset(); }*/ //还有就是用户在暂停是点击其他的音乐,所以不管当前状态,都重置一下 //下面这段代码可以实现简单的音乐播放 try { // Log.i(TAG,"palyer......new...."); mediaPlayer.reset(); mediaPlayer.setDataSource(url); mediaPlayer.setLooping(true); // mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepare(); mediaPlayer.start(); // 设置进度条最大值 MusicActivity.audioSeekBar.setMax(mediaPlayer.getDuration()); //开启新线程 new Thread(this).start(); } catch (IOException e) { e.printStackTrace(); } } // 刷新进度条 ,时间 @Override public void run() { Log.i(TAG,Thread.currentThread().getName()+"......run..."); int total = mediaPlayer.getDuration();// 总时长 while (mediaPlayer != null && currentPosition < total) { try { Thread.sleep(1000); if (mediaPlayer != null) { currentPosition = mediaPlayer.getCurrentPosition(); } } catch (InterruptedException e) { e.printStackTrace(); } MusicActivity.audioSeekBar.setProgress(CurrentPosition); } } @Override public void onDestroy() { Log.i(TAG,"onDestroy......"); super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } //关闭线程 Thread.currentThread().interrupt(); stopForeground(true); } public String toTime(int time){ time /= 1000; int minute = time / 60; int hour = minute / 60; int second = time % 60; minute %= 60; return String.format("%02d:%02d", minute, second); } }这样子搞不是不可以,但是官方提供的onbind方法没有使用,所以想使用一下,调用onbind放回一个service对象,在activity的连接部分获取到这个返回值,然后在activity里直接使用该对象的方法获取想要的数据,再添加上前台service,完成后的代码
package com.cl.android.music; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.util.Log; import java.io.IOException; public class MusicPlayerService extends Service {//implements Runnable { private static final String TAG = "MusicPlayerService"; private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台service public static MediaPlayer mediaPlayer = null; private String url = null; private String MSG = null; private static int curposition;//第几首音乐 private musicBinder musicbinder = null; private int currentPosition = 0;// 设置默认进度条当前位置 public MusicPlayerService() { Log.i(TAG,"MusicPlayerService......1"); musicbinder = new musicBinder(); } //通过bind 返回一个IBinder对象,然后改对象调用里面的方法实现参数的传递 @Override public IBinder onBind(Intent intent) { Log.i(TAG,"onBind......"); return musicbinder; } /** * 自定义的 Binder对象 */ public class musicBinder extends Binder { public MusicPlayerService getPlayInfo(){ return MusicPlayerService.this; } } //得到当前播放位置 public int getCurrentPosition(){ if(mediaPlayer != null){ int total = mediaPlayer.getDuration();// 总时长 if( currentPosition < total){ currentPosition = mediaPlayer.getCurrentPosition(); } } return currentPosition; } //得到当前播放位置 public int getDuration(){ return mediaPlayer.getDuration();// 总时长 } //得到 mediaPlayer public MediaPlayer getMediaPlayer(){ // if(mediaPlayer != null){ // return mediaPlayer; // } return mediaPlayer; } //得到 当前播放第几个音乐 public int getCurposition(){ return curposition; } @Override public void onCreate() { Log.i(TAG, "onCreate......2"); super.onCreate(); if (mediaPlayer == null) { /* mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer = null;*/ mediaPlayer = new MediaPlayer(); } // 监听播放是否完成 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { //我目前也不知道该干嘛 } }); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand......3"); // /storage/emulated/0/Music/Download/Selena Gomez - Revival/Hands to Myself.mp3 if(intent != null){ MSG = intent.getStringExtra("MSG"); if(MSG.equals("0")){ url = intent.getStringExtra("url"); curposition = intent.getIntExtra("curposition",0); Log.i(TAG, url + "......." + Thread.currentThread().getName()); palyer(); }else if(MSG.equals("1")){ mediaPlayer.pause(); }else if(MSG.equals("2")){ mediaPlayer.start(); } String name = "Current: "+ url.substring(url.lastIndexOf("/") + 1 , url.lastIndexOf(".")); Log.i(TAG,name); // //开启前台service Notification notification = null; if (Build.VERSION.SDK_INT < 16) { notification = new Notification.Builder(this) .setContentTitle("Enter the MusicPlayer").setContentText(name) .setSmallIcon(R.drawable.musicfile).getNotification(); } else { Notification.Builder builder = new Notification.Builder(this); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MusicActivity.class), 0); builder.setContentIntent(contentIntent); builder.setSmallIcon(R.drawable.musicfile); // builder.setTicker("Foreground Service Start"); builder.setContentTitle("Enter the MusicPlayer"); builder.setContentText(name); notification = builder.build(); } startForeground(NOTIFICATION_ID, notification); } return super.onStartCommand(intent, flags, startId); } private void palyer() { Log.i(TAG,"palyer......"); //如果正在播放,先停止再播放新的 /* if(mediaPlayer.isPlaying()){ Log.i(TAG,"palyer......running...."); // 暂停 mediaPlayer.pause(); mediaPlayer.reset(); }*/ //还有就是用户在暂停是点击其他的音乐,所以不管当前状态,都重置一下 //下面这段代码可以实现简单的音乐播放 try { // Log.i(TAG,"palyer......new...."); mediaPlayer.reset(); mediaPlayer.setDataSource(url); mediaPlayer.setLooping(true); // mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepare(); mediaPlayer.start(); // 设置进度条最大值 // MusicActivity.audioSeekBar.setMax(mediaPlayer.getDuration()); //开启新线程 // new Thread(this).start(); } catch (IOException e) { e.printStackTrace(); } } // 刷新进度条 ,时间 /* @Override public void run() { Log.i(TAG,Thread.currentThread().getName()+"......run..."); int total = mediaPlayer.getDuration();// 总时长 while (mediaPlayer != null && currentPosition < total) { try { Thread.sleep(1000); if (mediaPlayer != null) { currentPosition = mediaPlayer.getCurrentPosition(); } } catch (InterruptedException e) { e.printStackTrace(); } // MusicActivity.audioSeekBar.setProgress(CurrentPosition); } } */ @Override public boolean onUnbind(Intent intent) { Log.i(TAG,"onUnbind......"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { super.onRebind(intent); Log.i(TAG, "onRebind......"); } @Override public void onDestroy() { Log.i(TAG,"onDestroy......"); super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } //关闭线程 Thread.currentThread().interrupt(); stopForeground(true); } public String toTime(int time){ time /= 1000; int minute = time / 60; int hour = minute / 60; int second = time % 60; minute %= 60; return String.format("%02d:%02d", minute, second); } }activity那端,使用handler + runnable实现主线程的界面刷新,全部功能完成后的代码
package com.cl.android.music; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.database.Cursor; import android.media.MediaPlayer; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.widget.AdapterView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.SeekBar; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; import android.view.View.OnClickListener; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Timer; import java.util.TimerTask; public class MusicActivity extends AppCompatActivity { private ListView musicListView = null; private ImageView imageView = null; private ArrayList<Map<String, Object>> listems = null;//需要显示在listview里的信息 private ArrayList<MusicMedia> musicList = null; //音乐信息列表 // private ImageButton btn_previous = null,btn_play_pause = null,btn_next = null; private ImageView btn_play_pause = null; public static SeekBar audioSeekBar = null;//定义进度条 public static TextView textView = null; private Intent intent = null; private int currentposition = -1;//当前播放列表里哪首音乐 private boolean isplay = false;//音乐是否在播放 private MusicPlayerService musicPlayerService = null; private MediaPlayer mediaPlayer = null; private Handler handler = null;//处理界面更新,seekbar ,textview private boolean isservicerunning = false;//退出应用再进入时(点击app图标或者在通知栏点击service)使用,判断服务是否在启动 private SingleMusicInfo singleMusicInfo = null;//音乐的详细信息 private boolean isExit = false;//返回键 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_music); Log.i("MusicPlayerService", "MusicActivity...onCreate........." + Thread.currentThread().hashCode()); // init(); } private void init() { intent = new Intent(); intent.setAction("player"); intent.setPackage(getPackageName()); handler = new Handler(); imageView = (ImageView)findViewById(R.id.click_share); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT,"我的博客地址:http://blog.csdn.net/i_do_can"); shareIntent.setType("text/plain"); //设置分享列表 startActivity(Intent.createChooser(shareIntent,"分享到")); } }); textView = (TextView)findViewById(R.id.musicinfo); musicListView = (ListView)findViewById(R.id.musicListView); // btn_previous = (ImageButton)findViewById(R.id.previous); //播放暂停时要切换图标 // btn_play_pause = (ImageButton)findViewById(R.id.play_pause); btn_play_pause = (ImageView)findViewById(R.id.play_pause); // btn_next = (ImageButton)findViewById(R.id.next); musicListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //点击播放音乐,不过需要判断一下当前是否有音乐在播放,需要关闭正在播放的 //position 可以获取到点击的是哪一个,去 musicList 里寻找播放 currentposition = position; player(currentposition); } }); musicList = scanAllAudioFiles(); //这里其实可以直接在扫描时返回 ArrayList<Map<String, Object>>() listems = new ArrayList<Map<String, Object>>(); for (Iterator iterator = musicList.iterator(); iterator.hasNext();) { Map<String, Object> map = new HashMap<String, Object>(); MusicMedia mp3Info = (MusicMedia) iterator.next(); // map.put("id",mp3Info.getId()); map.put("title", mp3Info.getTitle()); map.put("artist", mp3Info.getArtist()); map.put("album", mp3Info.getAlbum()); // map.put("albumid", mp3Info.getAlbumId()); map.put("duration", mp3Info.getTime()); map.put("size", mp3Info.getSize()); map.put("url", mp3Info.getUrl()); map.put("bitmap", R.drawable.musicfile); listems.add(map); } /*SimpleAdapter的参数说明 * 第一个参数 表示访问整个android应用程序接口,基本上所有的组件都需要 * 第二个参数表示生成一个Map(String ,Object)列表选项 * 第三个参数表示界面布局的id 表示该文件作为列表项的组件 * 第四个参数表示该Map对象的哪些key对应value来生成列表项 * 第五个参数表示来填充的组件 Map对象key对应的资源一依次填充组件 顺序有对应关系 * 注意的是map对象可以key可以找不到 但组件的必须要有资源填充 因为 找不到key也会返回null 其实就相当于给了一个null资源 * 下面的程序中如果 new String[] { "name", "head", "desc","name" } new int[] {R.id.name,R.id.head,R.id.desc,R.id.head} * 这个head的组件会被name资源覆盖 * */ SimpleAdapter mSimpleAdapter = new SimpleAdapter( this, listems, R.layout.music_item, new String[] {"bitmap","title","artist", "size","duration"}, new int[] {R.id.video_imageView,R.id.video_title,R.id.video_singer,R.id.video_size,R.id.video_duration} ); //listview里加载数据 musicListView.setAdapter(mSimpleAdapter); //进度条 audioSeekBar = (SeekBar) findViewById(R.id.seekBar); //退出后再次进去程序时,进度条保持持续更新 if(MusicPlayerService.mediaPlayer!=null){ reinit();//更新页面布局以及变量相关 } //播放进度监 ,使用静态变量时别忘了Service里面还有个进度条刷新 audioSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (currentposition == -1) { Log.i("MusicPlayerService", "MusicActivity...showInfo(请选择要播放的音乐);........."); //还没有选择要播放的音乐 showInfo("请选择要播放的音乐"); } else { //假设改变源于用户拖动 if (fromUser) { //这里有个问题,如果播放时用户拖进度条还好说,但是如果是暂停时,拖完会自动播放,所以还需要把图标设置一下 btn_play_pause.setBackgroundResource(R.drawable.pause); MusicPlayerService.mediaPlayer.seekTo(progress);// 当进度条的值改变时,音乐播放器从新的位置开始播放 } } } @Override public void onStartTrackingTouch(SeekBar seekBar) { if (mediaPlayer != null) { mediaPlayer.pause(); } // MusicPlayerService.mediaPlayer.pause(); // 开始拖动进度条时,音乐暂停播放 } @Override public void onStopTrackingTouch(SeekBar seekBar) { if (mediaPlayer != null) { mediaPlayer.start(); } // MusicPlayerService.mediaPlayer.start(); // 停止拖动进度条时,音乐开始播放 } }); //textView 点击弹出音乐的详细信息 textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Log.i("MusicPlayerService", "MusicActivity...textView.setOnClickListener;........."); if (textView.getText().length() > 0) { singleMusicInfo = new SingleMusicInfo(MusicActivity.this,listems.get(currentposition)); //显示窗口 singleMusicInfo.showAtLocation(MusicActivity.this.findViewById(R.id.contentmusic), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置 } } }); Log.i("MusicPlayerService", "MusicActivity...init done;........."); } private void reinit() { //设置进度条最大值 // audioSeekBar.setMax(MusicPlayerService.mediaPlayer.getDuration()); // audioSeekBar.setProgress(MusicPlayerService.mediaPlayer.getCurrentPosition()); // currentposition = MusicPlayerService.getCurposition(); Log.i("MusicPlayerService","reinit........."); isservicerunning = true; //如果是正在播放 if(MusicPlayerService.mediaPlayer.isPlaying()){ isplay = true; btn_play_pause.setBackgroundResource(R.drawable.pause); } //重新绑定service bindService(intent, conn, Context.BIND_AUTO_CREATE); } /*加载媒体库里的音频*/ public ArrayList<MusicMedia> scanAllAudioFiles(){ //生成动态数组,并且转载数据 ArrayList<MusicMedia> mylist = new ArrayList<MusicMedia>(); /*查询媒体数据库 参数分别为(路径,要查询的列名,条件语句,条件参数,排序) 视频:MediaStore.Video.Media.EXTERNAL_CONTENT_URI 图片;MediaStore.Images.Media.EXTERNAL_CONTENT_URI */ Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); //遍历媒体数据库 if(cursor.moveToFirst()){ while (!cursor.isAfterLast()) { //歌曲编号 int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)); //歌曲标题 String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); //歌曲的专辑名:MediaStore.Audio.Media.ALBUM String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)); int albumId = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)); //歌曲的歌手名: MediaStore.Audio.Media.ARTIST String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)); //歌曲文件的路径 :MediaStore.Audio.Media.DATA String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)); //歌曲的总播放时长 :MediaStore.Audio.Media.DURATION int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)); //歌曲文件的大小 :MediaStore.Audio.Media.SIZE Long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE)); if (size >1024*800){//大于800K MusicMedia musicMedia = new MusicMedia(); musicMedia.setId(id); musicMedia.setArtist(artist); musicMedia.setSize(size); musicMedia.setTitle(tilte); musicMedia.setTime(duration); musicMedia.setUrl(url); musicMedia.setAlbum(album); musicMedia.setAlbumId(albumId); mylist.add(musicMedia); } cursor.moveToNext(); } } return mylist; } public void previous(View view) { previousMusic(); } public void play_pause(View view) { Log.i("MusicPlayerService", "MusicActivity...play_pause........." +isplay); //当前是pause的图标,(使用图标来判断是否播放,就不需要再新定义变量为状态了,表示没能找到得到当前背景的图片的)实际上播放着的,暂停 // if(btn_play_pause.getBackground().getCurrent().equals(R.drawable.play)){ if(isservicerunning){//服务启动着,这里点击播放暂停按钮时只需要当前音乐暂停或者播放就好 if (isplay) { pause(); } else { //暂停--->继续播放 player("2"); } }else { if (isplay) { pause(); } else { Log.i("MusicPlayerService", "MusicActivity...notplay........."); //当前是play的图标,是 暂停 着的 //初始化时,没有点击列表,直接点击了播放按钮 if (currentposition == -1) { showInfo("请选择要播放的音乐"); } else { //暂停--->继续播放 player("2"); } } } } public void next(View view) { nextMusic(); } private void player() { player(currentposition); } private void player(int position){ textView.setText(musicList.get(position).getTitle()+" playing..."); intent.putExtra("curposition", position);//把位置传回去,方便再启动时调用 intent.putExtra("url", musicList.get(position).getUrl()); intent.putExtra("MSG","0"); isplay = true; //播放时就改变btn_play_pause图标,下面这个过期了 // btn_play_pause.setBackgroundDrawable(getResources().getDrawable(R.drawable.pause)); btn_play_pause.setBackgroundResource(R.drawable.pause); startService(intent); bindService(intent, conn, Context.BIND_AUTO_CREATE); Log.i("MusicPlayerService","MusicActivity...bindService......."); } private ServiceConnection conn = new ServiceConnection() { /** 获取服务对象时的操作 */ public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub musicPlayerService = ((MusicPlayerService.musicBinder)service).getPlayInfo(); mediaPlayer = musicPlayerService.getMediaPlayer(); Log.i("MusicPlayerService", "MusicActivity...onServiceConnected......."); currentposition = musicPlayerService.getCurposition(); //设置进度条最大值 audioSeekBar.setMax(mediaPlayer.getDuration()); //这里开了一个线程处理进度条,这个方式官方貌似不推荐,说违背什么单线程什么鬼 // new Thread(seekBarThread).start(); //使用runnable + handler handler.post(seekBarHandler); } /** 无法获取到服务对象时的操作 */ public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub musicPlayerService = null; } }; //1s更新一次进度条 Runnable seekBarThread = new Runnable() { @Override public void run() { while (musicPlayerService != null) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // Log.i("MusicPlayerService", "seekBarThread run......."); audioSeekBar.setProgress(musicPlayerService.getCurrentPosition()); } } }; Runnable seekBarHandler = new Runnable() { @Override public void run() { Log.i("MusicPlayerService", "MusicActivity...seekBarHandler run......."+Thread.currentThread().hashCode()+" "+handler.hashCode()); audioSeekBar.setProgress(musicPlayerService.getCurrentPosition()); textView.setText( "(Click Me) "+ musicList.get(currentposition).getTitle() +" " + musicPlayerService.toTime(musicPlayerService.getCurrentPosition()) + " / " + musicPlayerService.toTime(musicPlayerService.getDuration() )); handler.postDelayed(seekBarHandler, 1000); } }; private void player(String info){ intent.putExtra("MSG",info); isplay = true; btn_play_pause.setBackgroundResource(R.drawable.pause); startService(intent); } /* * MSG : * 0 未播放--->播放 * 1 播放--->暂停 * 2 暂停--->继续播放 * * */ private void pause() { intent.putExtra("MSG","1"); isplay = false; btn_play_pause.setBackgroundResource(R.drawable.play); startService(intent); } private void previousMusic() { if(currentposition > 0){ currentposition -= 1; player(); }else{ showInfo("已经是第一首音乐了"); } } private void nextMusic() { if(currentposition < musicList.size()-2){ currentposition += 1; player(); }else{ showInfo("已经是最后一首音乐了"); } } private void showInfo(String info) { Toast.makeText(this,info,Toast.LENGTH_SHORT).show(); } @Override protected void onResume() { super.onResume(); Log.i("MusicPlayerService", "MusicActivity...onResume........." + Thread.currentThread().hashCode()); init(); } @Override protected void onPause() { super.onPause(); Log.i("MusicPlayerService", "MusicActivity...onPause........." + Thread.currentThread().hashCode()); //绑定服务了 if(musicPlayerService != null){ unbindService(conn); } handler.removeCallbacks(seekBarHandler); } @Override protected void onDestroy() { super.onDestroy(); // unbindService(conn); Log.i("MusicPlayerService", "MusicActivity...onDestroy........." + Thread.currentThread().hashCode()); } private void exit(String info) { if(!isExit) { isExit = true; Toast.makeText(this, info, Toast.LENGTH_SHORT).show(); new Timer().schedule(new TimerTask() { @Override public void run() { isExit = false; } }, 2000); } else { finish(); } } //按两次返回键退出 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { //音乐服务启动了,隐藏至通知栏 if(musicPlayerService != null){ exit("再按一次隐藏至通知栏"); }else{ exit("再按一次退出程序"); } } return false; } }
有个很奇怪的地方,完全不符合生命周期,按说应用不在界面上显示,再启动时,应该调用onRestart->onStart...
但是我测试时时直接OnCreate-onStart...好吧,很无奈,直接kill掉了,可能是我手机的问题,为了防止真的是手机的问题,我把初始化代码写在了onResume里
当前播放时间显示的部分,我添加了一个弹窗,点击可以显示当前播放歌曲的详细信息,弹窗继承PopupWindow,布局文件就一个TableLayout,就俩列,设置第二列内容自动换行
<?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="match_parent" > <TableLayout android:id="@+id/tablelayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:shrinkColumns="1"></TableLayout> </RelativeLayout>
弹窗点击非弹窗部分退出
package com.cl.android.music; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.ListView; import android.widget.PopupWindow; import android.view.ViewGroup.LayoutParams; import android.widget.SimpleAdapter; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; /** * Created by chenling on 2016/3/17. */ public class SingleMusicInfo extends PopupWindow { private View view; private TableLayout tableLayout; public SingleMusicInfo(Context context,Map<String, Object> map) { super(context); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.singlemusicinfo, null); tableLayout = (TableLayout) view.findViewById(R.id.tablelayout); map.remove("bitmap");//移除图片那个键值对 for(String keys : map.keySet()){ TableRow tableRow = new TableRow(context); TextView key = new TextView(context); TextView value = new TextView(context); Log.i("MusicPlayerService", "SingleMusicInfo..........." + tableRow.hashCode()); key.setText(" " + keys + " "); value.setText(map.get(keys).toString()); tableRow.addView(key); tableRow.addView(value); tableLayout.addView(tableRow); } //设置SingleMusicInfo的View this.setContentView(view); //设置弹出窗体的宽 this.setWidth(LayoutParams.MATCH_PARENT); //设置弹出窗体的高 this.setHeight(LayoutParams.WRAP_CONTENT); //设置S弹出窗体可点击 this.setFocusable(true); ColorDrawable dw = new ColorDrawable(Color.rgb(255,228,181)); //设置弹出窗体的背景 this.setBackgroundDrawable(dw); //view添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框 view.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { int height = view.findViewById(R.id.tablelayout).getTop(); int y=(int) event.getY(); if(event.getAction()==MotionEvent.ACTION_UP){ if(y<height){ dismiss(); } } return true; } }); } }Ok ,原谅我代码逻辑没有讲详细,代码都有注释,注释的代码部分可以直接忽略,还有分享功能,大家果断分享一下吧,谢谢
附件:源码下载:http://download.csdn.net/detail/i_do_can/9464424
- - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - 更新2016-04-09- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
新增列表上拉下滑时顶部和底部菜单栏消失
新增播放模式:单曲循环 随机播放 顺序播放
新增摇一摇根据当前播放模式切换歌曲
更新之后的apk:http://fir.im/5u9p
第一点,列表上拉下滑时顶部和底部菜单栏消失,关键是要监听onTouchLIstener,关键代码如下
private float mLastY = -1;// 标记上下滑动时上次滑动位置,滑动隐藏上下标题栏 private RelativeLayout musictop,musicbotom; musictop = (RelativeLayout)findViewById(R.id.music_top); musicbotom = (RelativeLayout)findViewById(R.id.music_bottom); //上下滚动时 musicListView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (mLastY == -1) { mLastY = event.getRawY(); } switch (event.getAction()) { case MotionEvent.ACTION_MOVE: //判断上滑还是下滑 if (event.getRawY() > mLastY) { //下滑显示bottom,隐藏top musictop.setVisibility(View.GONE); musicbotom.setVisibility(View.VISIBLE); } else if (event.getRawY() < mLastY) { //上滑,显示top,隐藏bottom musictop.setVisibility(View.VISIBLE); // musicbotom.setVisibility(View.INVISIBLE); musicbotom.setVisibility(View.GONE); } else { // deltaY = 0.0 时 musictop.setVisibility(View.VISIBLE); musicbotom.setVisibility(View.VISIBLE); mLastY = event.getRawY(); return false;//返回false即可响应click事件 } mLastY = event.getRawY(); break; default: // reset mLastY = -1; musictop.setVisibility(View.VISIBLE); musicbotom.setVisibility(View.VISIBLE); break; } return false; } });接着看看播放模式的改变,这个简单,用户看见的只是简单的图片的切换,我这里是使用了SharedPreferences 保存相关的信息,方便用户再次启动时更改显示图片,主要是保存当前的播放模式,主要代码如下:
public static SharedPreferences sharedPreferences; public static SharedPreferences.Editor editor;//保存播放模式 private ImageView playMode ,playaccelerometer; private int[] modepic = {R.drawable.ic_shuffle_black_24dp,R.drawable.ic_repeat_black_24dp,R.drawable.ic_repeat_one_black_24dp}; //默认随机播放 playMode = (ImageView)findViewById(R.id.play_mode); sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); editor = sharedPreferences.edit(); int playmode = sharedPreferences.getInt("play_mode", -1); if(playmode == -1){//没有设置模式,默认随机 editor.putInt("play_mode",0).commit(); }else{ changeMode(playmode); } //修改播放模式 单曲循环 随机播放 顺序播放 int clicktimes = 0; public void changeMode(View view) { switch (clicktimes){ case 0://随机 --> 顺序 clicktimes++; changeMode(clicktimes); break; case 1://顺序 --> 单曲 clicktimes++; changeMode(clicktimes); break; case 2://单曲 --> 随机 clicktimes = 0; changeMode(clicktimes); break; default: break; } } private void changeMode(int playmode) { editor.putInt("play_mode",playmode).commit(); playMode.setBackgroundResource(modepic[playmode]); }其实这里最关键的不是上面的代码,而是播放器里的控制,模式更改后,当前音乐播放完成后要根据用户选择的模式来播放新的音乐,需要设置监听 mediaPlayer.setOnCompletionListener,然后根据 SharedPreferences 里的模式来播放音乐,是顺序播放还是随机播放,我的services里没有音乐列表,所以需要从activity里先获取音乐列表,以及当前播放的哪首音乐,
单曲循环时播放器的url不需要更改,顺序播放时取得下一首位置:curposition = (++curposition) % musiclist.size()
随机播放时取得下一首位置:curposition = (new Random()).nextInt(musiclist.size());
关键代码如下
// 监听播放是否完成 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { //我目前也不知道该干嘛,下一首嘛 playnew(); } }); private void playnew() { switch (MusicActivity.sharedPreferences.getInt("play_mode",-1)){ case 0://随机 curposition = (new Random()).nextInt(musiclist.size()); url = musiclist.get(curposition ).getUrl(); palyer(); break; case 1://顺序 curposition = (++curposition) % musiclist.size(); url = musiclist.get(curposition ).getUrl(); palyer(); break; case 2://单曲 url = musiclist.get(curposition ).getUrl(); palyer(); break; default: break; } }以上基本就可以实现自己控制播放模式了,
<!--震动--> <uses-permission android:name="android.permission.VIBRATE"/>摇一摇需要用到加速传感器,传感器Android底层都给我们实现好了,直接实现接口implements SensorEventListener
主要代码:
private SensorManager sensorManager = null;//传感器 private Vibrator vibrator = null;//震动 sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); //取得震动服务的句柄 vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE); //加速度传感器(accelerometer)、陀螺仪(gyroscope)、环境光照传感器(light)、磁力传感器(magnetic field)、方向传感器(orientation)、压力传感器(pressure)、距离传感器(proximity)和温度传感器(temperature)。 // http://www.open-open.com/lib/view/open1378259498734.html sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); @Override public void onSensorChanged(SensorEvent event) { if(MusicActivity.sharedPreferences.getInt("play_accelerometer",0) == 0){ // 传感器报告新的值 int sensorType = event.sensor.getType(); //values[0]:X轴,values[1]:Y轴,values[2]:Z轴 float[] values = event.values; if (sensorType == Sensor.TYPE_ACCELEROMETER) { if ((Math.abs(values[0]) > 17 || Math.abs(values[1]) > 17 || Math .abs(values[2]) > 17)) { Log.i("slack", "sensor x values[0] = " + values[0]); Log.i("slack", "sensor y values[1] = " + values[1]); Log.i("slack", "sensor z values[2] = " + values[2]); playnew(); //摇动手机后,再伴随震动提示~~ vibrator.vibrate(500); } } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { //传感器精度的改变 }基本就完成了
附件:module源码下载:http://download.csdn.net/detail/i_do_can/9485662
git地址:https://github.com/CL-window/Music