入职没多久,自学了一段时间的安卓基础知识,抱着巩固下基础以及学会对知识点的基本运用的初衷写了一个音乐播放器,因此用到的东西都是很基础的,功能什么的大部分都是按照自己的想法来实现的,如果看完感觉哪些地方写的不行或有好的建议欢迎给我留言.
该Android音乐播放器代码量稍微有点多,这里我将以实现功能的顺序为参考将音乐播放器分为几篇博客发布.该播放器实现的主要功能如下(结尾将会附上源代码下载地址):
1.本地音乐的播放及控制;
2.音乐播放界面的展示;
3.在线音乐的搜索及展示(包含使用json解析数据);
4.在线音乐的试听及下载;
5.下载控制界面-下载歌曲的暂停/继续/删除(可以查看并删除已下载音乐);
6.播放界面歌手专辑图片及歌词的下载和显示;
7.歌词的滚动显示以及滑动歌词改变音乐进度的监听;
8.音乐的断点下载;
9.基于PopupWindow的弹出式菜单(支持透明度修改和自定义背景);
10.后台任务栏显示与控制音乐的播放;
本地音乐列表
音乐播放界面
下面讲述项目需要实现的第一步功能-本地音乐播放的实现
这里主要涉及三个类:
1.MainActivity.java 负责整个项目的业务控制,包括滑动切换Fragment,控制音乐播放,呼出菜单等;
2.MusicListFragment.java 第一个Fragment展示在用户面前,主要展示本地音乐提供给用户点击播放;
3.MusicService.java 负责后台运行播放MediaPlayer
主要业务代码如下:
1MainActivity.java
package com.example.comfortmusic_1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import com.example.comfortmusic_1.fragment.DownloadFragment;
import com.example.comfortmusic_1.fragment.MusicListFragment;
import com.example.comfortmusic_1.fragment.NetFragment;
import com.example.comfortmusic_1.service.MusicService;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.ActionBar.Tab;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.app.FragmentTransaction;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.NavUtils;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.method.ScrollingMovementMethod;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RemoteViews;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends FragmentActivity implements MusicListFragment.Callbacks {
public static boolean isPlaying = false;//全局变量,表征当前是否在播放
/**
* 当前播放音乐的信息
*/
public static int currentMusicPosition;
public static String currentMusicTitle;
public static String currentMusicArtist;
public static String currentMusicDuration;
public static String currentMusicUrl;
/**
* 循环控制-CYCLE表示当前循环模式
*/
public static final int CYCLE_LIST = 1;
public static final int CYCLE_RANDOM = 2;
public static final int CYCLE_SINGLE = 3;
public static int CYCLE = CYCLE_LIST;
/**
* 发送给MusicService的播放信息MSG:从头开始播放/暂停/继续播放/换歌
*/
public static final int MSG_PLAY = 0;
public static final int MSG_PAUSE = 1;
public static final int MSG_CONTINUEPLAYING = 2;
public static final int MSG_CHANGESONG = 3;
public static int MSG = MSG_PLAY;
//屏幕的长度和宽度
public static int screenWidth;
public static int screenHeight;
//上一首歌曲位置,用来判断是从头播放还是继续播放,若prePosition=currentMusicPosition则继续播放,反之从头播放
public static int prePosition;
//程序启动时获取音频数据库中的音乐信息并保存到dbMusic中
public static List
2.MusicListFragment.java
package com.example.comfortmusic_1.fragment;
import java.util.Map;
import com.example.comfortmusic_1.MainActivity;
import com.example.comfortmusic_1.R;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AbsListView.LayoutParams;
import android.widget.AdapterView.OnItemClickListener;
public class MusicListFragment extends Fragment {
private Callbacks mCallbacks;
public static ListView musicList;//音乐列表
BaseAdapter musicListAdapter;//音乐列表适配器
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("action.refreshmusiclistFragment");
this.getActivity().registerReceiver(refreshReceiver, intentFilter);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.musiclist_main, container, false);
musicList = (ListView) rootView.findViewById(R.id.musiclist);
musicListAdapter = getAdapter();
musicList.setAdapter(musicListAdapter);
musicList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position,long id) {//播放选中歌曲
MainActivity.currentMusicPosition = position;
MainActivity.isPlaying = true;
MainActivity.MSG = MainActivity.MSG_PLAY;
mCallbacks.onItemSelected(position);//回调实现Callbacks的MainActivity.onItemSelected(position);
}
});
musicList.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
return false;
}
});
return rootView;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("activity 必须实现Callbacks接口!");
}
mCallbacks = (Callbacks)activity;
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
public interface Callbacks {
public void onItemSelected(Integer id);
}
public BaseAdapter getAdapter() {
BaseAdapter adapter = new BaseAdapter() {
@Override
public int getCount() {
return MainActivity.dbMusic.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
Map item = MainActivity.dbMusic.get(position);
LinearLayout line = new LinearLayout(MusicListFragment.this.getActivity());
line.setOrientation(LinearLayout.VERTICAL);
LinearLayout upLayout = new LinearLayout(MusicListFragment.this.getActivity());
upLayout.setOrientation(LinearLayout.HORIZONTAL);
ImageView musicTag = new ImageView(MusicListFragment.this.getActivity());
musicTag.setImageResource(R.drawable.music);
musicTag.setLayoutParams(new LayoutParams(80,80));
TextView musicTitle = new TextView(MusicListFragment.this.getActivity());
TextView musicArtist = new TextView(MusicListFragment.this.getActivity());
TextView musicDuration = new TextView(MusicListFragment.this.getActivity());
musicTitle.setText((String)item.get("title"));
musicTitle.setWidth(MainActivity.screenWidth/2);
musicTitle.setTextSize(18);
musicTitle.setTextColor(Color.MAGENTA);
musicTitle.setMaxLines(1);
musicDuration.setText((String)item.get("duration"));
musicDuration.setWidth(MainActivity.screenWidth/2);
musicDuration.setGravity(Gravity.RIGHT);
musicDuration.setTextColor(Color.MAGENTA);
musicDuration.setPaddingRelative(0, 0, 50, 0);
musicDuration.setMaxLines(1);
musicArtist.setText((String)item.get("artist"));
// musicArtist.setWidth(MainActivity.screenWidth/4);
musicArtist.setMaxLines(1);
// musicArtist.setTextColor(Color.argb(50, 255, 100, 0));
musicArtist.setPaddingRelative(80, 0, 0, 0);
upLayout.addView(musicTag);
upLayout.addView(musicTitle);
upLayout.addView(musicDuration);
line.addView(upLayout);
line.addView(musicArtist);
return line;
}
};
return adapter;
}
@Override
public void onDestroy() {
super.onDestroy();
this.getActivity().unregisterReceiver(refreshReceiver);
}
private BroadcastReceiver refreshReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("action.refreshmusiclistFragment")) {
Log.d("MusicListFragment", "receive refresh music list!");
// Toast.makeText(MusicListFragment.this.getActivity(), "receive update progress!", 200).show();
musicList.setAdapter(getAdapter());
}
}
};
}
3.MusicService.java
package com.example.comfortmusic_1.service;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import com.example.comfortmusic_1.MainActivity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MusicService extends Service {
private MediaPlayer musicPlayer = new MediaPlayer();
public static int musicPosition;
private Timer timer;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "musicservice_onStartCommand",500).show();
Log.d("MusicService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MusicService", "_onCreate");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("action.changesong");
registerReceiver(updateReceiver, intentFilter);
timer = new Timer();
}
//根据播放信息准备播放音乐
private void prepareMusic(Intent intent) {
Log.d("MusicService", "prepareMusic");
if (MainActivity.MSG == MainActivity.MSG_PLAY ) {
play();//从头开始播放一首歌
} else if (MainActivity.MSG == MainActivity.MSG_PAUSE) {
pause();//暂停播放当前歌曲
} else if (MainActivity.MSG == MainActivity.MSG_CONTINUEPLAYING) {
continuePlaying();//继续播放未完的歌曲
}
}
//继续播放
private void continuePlaying() {
Log.d("MusicService", "continuePlaying");
musicPlayer.start();
}
//从头开始播放一首歌
private void play() {
new Thread(new Runnable() {
@Override
public void run() {
if (musicPlayer.isPlaying()) {
musicPlayer.stop();
}
try {
musicPosition = 0;
musicPlayer.reset();
musicPlayer.setDataSource(MainActivity.currentMusicUrl);
musicPlayer.prepare();
musicPlayer.start();
musicPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
Intent completeIntent = new Intent();
completeIntent.setAction("action.nextsong");
sendBroadcast(completeIntent);
Log.d("MusicService", "sendBroadcast");
}
});
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(MusicService.this, "加载音乐失败,请检查网络链接!",500).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
//暂停播放
private void pause() {
Log.d("MusicService", "pause");
musicPlayer.pause();
musicPosition = musicPlayer.getCurrentPosition();
timer.cancel();
}
@Override
public void onDestroy() {
super.onDestroy();
if (musicPlayer != null) {
if (musicPlayer.isPlaying()) timer.cancel();
musicPlayer.stop();
musicPlayer.release();
}
this.unregisterReceiver(updateReceiver);
}
private BroadcastReceiver updateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("action.changesong")) {
prepareMusic(intent);
}
}
};
}
其中NetFragment和DownloadFragment只需继承Fragment即可看到程序运行效果
Android本地及网络音乐播放器源码下载