上一节实现了播放的功能,下面实现播放音乐时底部显示对应歌曲信息的功能。
【效果图】
【开发步骤】 1、xml 界面 2、当点击 ListView 中的 item 时,把播放列表和 position 存入 application 3、每当 service 开始播放音乐时,发送自定义广播 4、在Activity 中编写广播接收器接受该广播,获取当前正在播放的歌曲信息,更新界面(注意在 onCreate 及 onDestroy中注册以及取消注册) 5、更新 UI 时,我们需要通过 path 路径,获取 Bitmap
BitmapUtils.loadBitmap(String path,Callback){
异步发送http请求
调用 callback 回调方法 执行后续业务
}
按照开发步骤写代码:
主要布局中 activity_test.xml 中增加
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#ffffff" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#2894FF"
android:gravity="center_vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_music_thumb"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="10dp"
android:src="@mipmap/ic_launcher" />
<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
需要在 build.gradle 中引入依赖
implementation 'de.hdodenhof:circleimageview:3.1.0'
在点击播放歌曲后,底部显示对应歌曲信息,需要知道当前播放的歌曲是哪一首,我们可以存歌曲列表和点击的 position 来确定歌曲,可以用Application 实现
创建 MusicApplication
public class MusicApplication extends Application {
private List<MusicItem> musicList;
private int position;
public static MusicApplication app;
@Override
public void onCreate() {
super.onCreate();
app = this;
}
public static MusicApplication getApp() {
return app;
}
public List<MusicItem> getMusicList() {
return musicList;
}
public void setMusicList(List<MusicItem> musicList) {
this.musicList = musicList;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public MusicItem getCurrentMusic() {
return musicList.get(position);
}
}
AndroidManifest 中注册
<application
android:name=".application.MusicApplication"
......
android:theme="@android:style/Theme.Light.NoTitleBar">
<service android:name=".service.PlayMusicService"/>
......
</application>
NewMusicListFragment 中,在点击 listview 时,在 application 中存入音乐播放列表和 position
private void setListeners() {
listView.setOnItemClickListener((adapterView, view, i, l) -> {
final MusicItem music = musics.get(i);
String songId = music.id;
Toast.makeText(getActivity(), "position:" + i, Toast.LENGTH_SHORT).show();
model.loadMusicInfoBySongId(songId, new MusicInfoCallback() {
@Override
public void onMusicInfoLoaded(MusicItem musicItem) {
music.url = musicItem.url;
Log.d("TTT", music.url);
MusicApplication app = MusicApplication.getApp();
app.setMusicList(musics);
app.setPosition(i);
binder.playMusic(music.url);
}
});
});
}
当音乐播放开始时,service 通知 activity 播放开始,因此我们需要发送广播,PlayMusicService 中修改:
@Override
public void onCreate() {
super.onCreate();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
Intent intent = new Intent (Globalconsts.ACTION_MUSIC_STARTED);
sendBroadcast(intent);
}
});
}
创建常量类 GlobalConsts
public class Globalconsts {
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 {
void onBitmapLoaded(Bitmap bitmap);
}
Activity 中注册接收器
MusicInfoBroadCastReceiver receiver;
private ImageView imgMusicThumb;
private TextView tvMusicTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
......
bindMusicService();
registMusicReceiver();
}
private void setViews() {
......
viewPager = findViewById(R.id.viewpager);
imgMusicThumb = findViewById(R.id.img_music_thumb);
tvMusicTitle = findViewById(R.id.tv_music_title);
}
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();
MusicItem music = app.getCurrentMusic();
String pic = music.albumPic;
final String title = music.name;
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);
}
});
|