版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010356768/article/details/83182691
效果图
创建PlayMusicService
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import java.io.IOException;
/**
* 播放音乐服务
*/
public class PlayMusicService extends Service {
//Service是单例的,只创建1次,因此在这里创建MediaPlayer,保证只有一个
private MediaPlayer mediaPlayer = new MediaPlayer();
/**
* 当service实例创建时执行
*/
@Override
public void onCreate() {
super.onCreate();
//给mediaPlayer加监听
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
//音乐已经准备好
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MusicBinder();
}
public class MusicBinder extends Binder{
//定义供客户端调用的方法
public void playMusic(String url){
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();//异步准备
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
AndroidManifest.xml
对service进行注册
<service android:name=".service.PlayMusicService"/>
MainActivity中绑定Service
public class MainActivity extends FragmentActivity {
......
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setViews();
//设置ViewPager适配器
setViewPagerAdapter();
//设置监听
setListeners();
//绑定Service
bindMusicService();
}
/**
* 绑定Service
*/
private void bindMusicService() {
Intent intent = new Intent(this, PlayMusicService.class);
conn = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
PlayMusicService.MusicBinder binder = (PlayMusicService.MusicBinder)iBinder;
//把binder对象交给Fragment
NewMusicListFragment f1 = (NewMusicListFragment)fragments.get(0);
f1.setMusicBinder(binder);
}
//绑定成功执行该方法
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
this.bindService(intent,conn, Service.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
this.unbindService(conn);
super.onDestroy();
}
......
}
NewMusicListFragment中调用service中播放音乐方法
/**
* 新歌榜列表
*/
public class NewMusicListFragment extends Fragment {
......
private PlayMusicService.MusicBinder binder;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
private void setListeners() {
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
final Music music = musics.get(i);
String songId = music.getSong_id();
Toast.makeText(getActivity(),"position:"+i,Toast.LENGTH_SHORT).show();
//执行业务层 加载这首歌曲的基本信息
model.loadMusicInfoBySongId(songId, new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(Songinfo songinfo, BitrateModel bitrateModel) {
music.setSonginfo(songinfo);
music.setBitrate(bitrateModel);
//准备通过url地址执行播放业务
String fileLink = bitrateModel.getFile_link();
//播放音乐
binder.playMusic(fileLink);
}
});
}
});
}
......
}
上面实现了播放的功能,下面实现播放音乐时底部显示对应歌曲信息的功能
界面显示
activity_main增加以下布局
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="@color/colorPrimary"
>
<com.example.xx.v4.ui.CircleImageView
android:id="@+id/img_music_thumb"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@mipmap/ic_launcher"
android:layout_marginRight="10dp"/>
<TextView
android:id="@+id/tv_music_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="歌名"
android:textColor="@android:color/white"/>
</LinearLayout>
其中圆形头像用的CircleImageView,可以直接把Github项目中的CircleImageView.java和res下的attrs复制到项目中用即可
https://github.com/hdodenhof/CircleImageView
在点击播放歌曲后,底部显示对应歌曲信息,需要知道当前播放的歌曲是哪一首,我们可以存歌曲列表和点击的position来确定歌曲,可以用Application实现
创建MusicApplication
public class MusicApplication extends Application {
private List<Music> musicList;
private int position;
public static MusicApplication app;
@Override
public void onCreate() {
super.onCreate();
app = this;
}
public static MusicApplication getApp(){
return app;
}
public List<Music> getMusicList() {
return musicList;
}
public void setMusicList(List<Music> musicList) {
this.musicList = musicList;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
/**
* 获取当前正在播放的音乐
* @return
*/
public Music getCurrentMusic(){
return musicList.get(position);
}
}
AndroidManifest中注册
<application
android:name=".MusicApplication"
......
android:theme="@android:style/Theme.Light.NoTitleBar">
<service android:name=".service.PlayMusicService"/>
......
</application>
NewMusicListFragment中,在点击listview时,在application中存入音乐播放列表和position
private void setListeners() {
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l) {
final Music music = musics.get(i);
String songId = music.getSong_id();
Toast.makeText(getActivity(),"position:"+i,Toast.LENGTH_SHORT).show();
//执行业务层 加载这首歌曲的基本信息
model.loadMusicInfoBySongId(songId, new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(Songinfo songinfo, BitrateModel bitrateModel) {
music.setSonginfo(songinfo);
music.setBitrate(bitrateModel);
//把当前播放列表和position都存入application
MusicApplication app = MusicApplication.getApp();
app.setMusicList(musics);
app.setPosition(i);
//准备通过url地址执行播放业务
String fileLink = bitrateModel.getFile_link();
//播放音乐
binder.playMusic(fileLink);
}
});
}
});
}
当音乐播放开始时,service通知activity播放开始
因此我们需要发送广播
PlayMusicService中
/**
* 当service实例创建时执行
*/
@Override
public void onCreate() {
super.onCreate();
//给mediaPlayer加监听
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
//音乐已经准备好
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
//发送广播,通知activity音乐已经开始播放
Intent intent = new Intent (Globalconsts.ACTION_MUSIC_STARTED);
sendBroadcast(intent);
}
});
}
创建常量类GlobalConsts
/**
* 常量类
*/
public class Globalconsts {
//音乐开始播放 广播action
public static final String ACTION_MUSIC_STARTED = "ACTION_MUSIC_STARTED";
}
BitmapUtils中增加根据图片路径加载bitmap的方法
public static void loadBitmap(final String path, final BitmapCallback bitmapCallback){
AsyncTask<String,String,Bitmap> task = new AsyncTask<String, String, Bitmap>() {
@Override
protected Bitmap doInBackground(String... strings) {
try {
//先从内存缓存中读
//再从文件中读
String filename = path.substring(path.lastIndexOf("/")+1);
File file = new File(MusicApplication.getApp().getCacheDir(),"images/"+filename);
Bitmap b = bitmap(file);
if(b!=null){
return b;
}
InputStream is = HttpUtils.getInputStream(path);
b = BitmapFactory.decodeStream(is);
//下载下来的图片,存入缓存中
save(b,file);
return b;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//主线程中执行回调方法
@Override
protected void onPostExecute(Bitmap bitmap) {
bitmapCallback.onBitmapLoaded(bitmap);
}
};
task.execute();
}
增加接口BitmapCallback
public interface BitmapCallback {
/**
* 当图片下载成功之后的回调方法
* @param bitmap
*/
void onBitmapLoaded(Bitmap bitmap);
}
注册接收器
MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setViews();
//设置ViewPager适配器
setViewPagerAdapter();
//设置监听
setListeners();
//绑定Service
bindMusicService();
//注册广播接收器
registMusicReceiver();
}
/**
* 注册广播接收器
*/
private void registMusicReceiver() {
receiver = new MusicInfoBroadCastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Globalconsts.ACTION_MUSIC_STARTED);
this.registerReceiver(receiver,intentFilter);
}
/**
* 接收音乐信息的广播接收器
*/
class MusicInfoBroadCastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(Globalconsts.ACTION_MUSIC_STARTED)){
//开始播放音乐,获取当前音乐对象
MusicApplication app = MusicApplication.getApp();
Music music = app.getCurrentMusic();
String pic = music.getPic_small();
final String title = music.getTitle();
BitmapUtils.loadBitmap(pic, new BitmapCallback() {
@Override
public void onBitmapLoaded(Bitmap bitmap) {
if(bitmap != null){
imgMusicThumb.setImageBitmap(bitmap);
}
}
});
tvMusicTitle.setText(title);
}
}
}
@Override
protected void onDestroy() {
this.unbindService(conn);
this.unregisterReceiver(receiver);
super.onDestroy();
}
现在让图片转起来
MusicInfoBroadCastReceiver中在设置完图片后,设置动画
BitmapUtils.loadBitmap(pic, new BitmapCallback() {
@Override
public void onBitmapLoaded(Bitmap bitmap) {
if(bitmap != null){
imgMusicThumb.setImageBitmap(bitmap);
//执行旋转动画
RotateAnimation animation = new RotateAnimation(0,360,imgMusicThumb.getWidth()/2,imgMusicThumb.getWidth()/2);
animation.setDuration(10000);
animation.setRepeatCount(Animation.INFINITE);
animation.setInterpolator(new LinearInterpolator());//匀速旋转
imgMusicThumb.startAnimation(animation);
}
tvMusicTitle.setText(title);
}
});