用SERVICE结合ACTIVITY完成自己的播放器

1.Service介绍

作为Android四大组件之一,想必有非常打的功用。那么这个公用可以干什么呢?他可以帮你在后台帮你做不需要与UI相关的事,例如做长连接的时候需要保持心跳啊,这种就可以用Service来做。有人说那不有点像线程,做一个心跳保持连接不就好了吗?虽然这话不假,但是这是错误的,第一,他不像为了去做通信连接不能再UI线程中启用,就去起个工作线程去跑。而是在后台做自己的事,没有与前台交互(有可能有那么一点,或者说获得相关的事例也是可以操作的);第二,其实Service也是UI线程里的,哪有人说,那怎么去做长连接通信呢,同样你也要去起线程的。

说成这样不知道大家理解了没有。下面回归正题,直接上代码。

2.Service一般写法

以下代码是Service的一般写法和通用写法,为了是在Activity绑定Service然后产生myService的事例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class myService extends Service {
public final IBinder binder = new MyBinder();

public MusicService() {

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
return binder;
}

public class MyBinder extends Binder {
public MusicService getService() {
return MusicService.this;
}

}
}

对应Activity的代码如下:绑定Service拿到mySevice实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myService = ((myService.MyBinder) iBinder).getService();
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
myService = null;
}
};

private void bindServiceConnection() {
Intent intent = new Intent(*******.this, myService.class);
startService(intent);
bindService(intent, sc, this.BIND_AUTO_CREATE);
}

3.用Service做一个属于自己的播放器

MusicService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
public class MusicService extends Service {
public final IBinder binder = new MyBinder();

public ArrayList<MusicInfo> getMusicDir() {
return musicDir;
}

public void setMusicDir(ArrayList<MusicInfo> musicDir) {
this.musicDir = musicDir;
}

private ArrayList<MusicInfo> musicDir;
private int musicIndex = 0;
public static MediaPlayer mp = new MediaPlayer();
public static Boolean I$Initial = false;

public MusicService() {
musicDir = new ArrayList<>();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
return binder;
}


public void addMusic(MusicInfo MusicPath) {
musicDir.add(MusicPath);
try {
mp.reset();
mp.setDataSource(musicDir.get(musicDir.size()-1).getMusicPath());
mp.prepare();
I$Initial = true;
} catch (IOException e) {
e.printStackTrace();
}

}

public void playOrPause() {
if (mp.isPlaying()) {
mp.pause();
} else {
mp.start();
}
}

public void stop() {
if (mp != null) {
mp.stop();
try {
mp.prepare();
mp.seekTo(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}

public void nextMusic() {
if (mp != null && musicIndex < 3) {
mp.stop();
try {
mp.reset();
mp.setDataSource(musicDir.get(musicIndex + 1).getMusicPath());
musicIndex++;
mp.prepare();
mp.seekTo(0);
mp.start();
} catch (Exception e) {
KLog.d("hint", "can't jump next music");
e.printStackTrace();
}
}
}

public void preMusic() {
if (mp != null && musicIndex > 0) {
mp.stop();
try {
mp.reset();
mp.setDataSource(musicDir.get(musicIndex - 1).getMusicPath());
musicIndex--;
mp.prepare();
mp.seekTo(0);
mp.start();
} catch (Exception e) {
KLog.d("hint", "can't jump pre music");
e.printStackTrace();
}
}
}

public class MyBinder extends Binder {
public MusicService getService() {
return MusicService.this;
}

}
}

播放器界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
public class PlayMusicActivity extends Activity implements View.OnClickListener {

private MusicService musicService;
private SeekBar MusicSeekBar;
private TextView MusicTime, MusicCurrentTime, MusicName;
private ImageView btnPlayOrPause, ic_list, adjustVolume, MusicAlbumCover;
private Handler handler;
private String path;
private Animation operatingAnim;
private final int FILE_SELECT_CODE = 1;
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
musicService = ((MusicService.MyBinder) iBinder).getService();
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
musicService = null;
}
};

private void bindServiceConnection() {
Intent intent = new Intent(PlayMusicActivity.this, MusicService.class);
startService(intent);
bindService(intent, sc, this.BIND_AUTO_CREATE);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_play_music);
KLog.d("hint", "ready to new MusicService");
//musicService = new MusicService();
KLog.d("hint", "finish to new MusicService");
//绑定服务
bindServiceConnection();
//初始化控件
init();
doPlayMusic();


}

private void doPlayMusic() {
// MusicSeekBar.setProgress(musicService.mp.getCurrentPosition());
// MusicSeekBar.setMax(musicService.mp.getDuration());
// musicStatus = (TextView)this.findViewById(R.id.MusicStatus);
}

public Runnable runnable = new Runnable() {
@Override
public void run() {
if (musicService.mp.isPlaying()) {
MusicCurrentTime.setText(MilliSecondDurtion2TimeFormat.Ms2TimeStringFormat(musicService.mp.getCurrentPosition()));
MusicSeekBar.setProgress(musicService.mp.getCurrentPosition());
}

MusicSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//musicService.playOrPause();
musicService.mp.seekTo(seekBar.getProgress());
// musicService.playOrPause();
}
});
handler.postDelayed(runnable, 100);
}
};


@Override
protected void onResume() {
MusicSeekBar.setProgress(0);
handler = new Handler();
handler.post(runnable);
musicService.mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
MediaPlayer mp1 = new MediaPlayer();
try {
mp1.setDataSource(musicService.getMusicDir().get(musicService.getMusicDir().size() - 1).getMusicPath());
mp1.prepare();
} catch (IOException e) {
e.printStackTrace();
}

MusicCurrentTime.setText(MilliSecondDurtion2TimeFormat.Ms2TimeStringFormat(mp.getDuration()));
btnPlayOrPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_play_music));
MusicAlbumCover.clearAnimation();
}
});
super.onResume();
}

private void init() {
MusicAlbumCover = (ImageView) findViewById(R.id.MusicAlbumCover);
operatingAnim = AnimationUtils.loadAnimation(this, R.anim.tip);
LinearInterpolator lin = new LinearInterpolator();
operatingAnim.setInterpolator(lin);
MusicSeekBar = (SeekBar) findViewById(R.id.MusicSeekBar1);
ic_list = (ImageView) findViewById(R.id.ic_list);
adjustVolume = (ImageView) findViewById(R.id.adjustVolume);
MusicTime = (TextView) this.findViewById(R.id.MusicTime);
btnPlayOrPause = (ImageView) this.findViewById(R.id.BtnPlayorPause);
MusicCurrentTime = (TextView) findViewById(R.id.MusicCurrentTime);
MusicName = (TextView) findViewById(R.id.MusicName);
MusicSeekBar.setEnabled(false);
ic_list.setOnClickListener(this);
adjustVolume.setOnClickListener(this);
btnPlayOrPause.setOnClickListener(this);


}

@Override
public void onDestroy() {
unbindService(sc);
super.onDestroy();
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.BtnPlayorPause:
if (musicService.getMusicDir().size() <= 0) {
Toast.makeText(this, "您的列表为空", Toast.LENGTH_SHORT).show();
} else {
if (musicService.mp.isPlaying()) {
MusicAlbumCover.clearAnimation();
btnPlayOrPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_play_music));
} else {
if (operatingAnim != null) {
MusicAlbumCover.startAnimation(operatingAnim);
}
btnPlayOrPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_pause_music));
}
musicService.playOrPause();

}
break;
case R.id.ic_list:
if (musicService.mp.isPlaying()) {
btnPlayOrPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_play_music));
musicService.playOrPause();
}
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
Log.i("file", "===================");
try {
startActivityForResult(intent, FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(getApplication(), "Please install a File Manager.", Toast.LENGTH_SHORT).show();
}
break;
case R.id.adjustVolume:
showPopupWindow(v);
break;
default:
break;
}
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case FILE_SELECT_CODE:
if (resultCode == RESULT_OK) {
// Get the Uri of the selected file
Uri uri = data.getData();
path = FileUtils.getPhotoPathFromContentUri(getApplication(), uri);
Log.i("File's Path is", path + "");
if (path != null) {
String splitPath[] = path.split("\\/");
String MusicNameInPath[] = splitPath[splitPath.length - 1].split("\\.");
MusicName.setText(MusicNameInPath[MusicNameInPath.length - 2]);
MusicInfo musicInfo = new MusicInfo();
musicInfo.setMusicPath(path);
musicService.addMusic(musicInfo);

try {
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(musicService.getMusicDir().get(musicService.getMusicDir().size() - 1).getMusicPath());
mp.prepare();
MusicCurrentTime.setText("00:00");
MusicTime.setText(MilliSecondDurtion2TimeFormat.Ms2TimeStringFormat(mp.getDuration()));
MusicSeekBar.setMax(musicService.mp.getDuration());
MusicSeekBar.setProgress(0);
musicService.playOrPause();
if (operatingAnim != null) {
MusicAlbumCover.startAnimation(operatingAnim);
}
btnPlayOrPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_pause_music));
MusicSeekBar.setEnabled(true);
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(getApplication(), "文件管理器异常。", Toast.LENGTH_LONG).show();
}


}

break;
}
}

private void showPopupWindow(View view) {

// 一个自定义的布局,作为显示的内容
View contentView = LayoutInflater.from(this).inflate(
R.layout.popwindow_adjust_volume, null);

final PopupWindow popupWindow = new PopupWindow(contentView,
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);

int popupWidth = view.getMeasuredWidth(); // 获取测量后的宽度
int popupHeight = view.getMeasuredHeight(); //获取测量后的高度
int[] location = new int[2];
view.getLocationOnScreen(location);
View ParentView = (View) view.getParent();
int ParentViewHeight = ParentView.getHeight();
popupWindow.showAtLocation(view, Gravity.NO_GRAVITY, (location[0] + view.getWidth() / 2) - popupWidth / 2, location[1] - popupHeight - ParentViewHeight+(ParentViewHeight-popupHeight)/2);
popupWindow.setTouchable(true);
popupWindow.setTouchInterceptor(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
KLog.i("mengdd", "onTouch : ");

return false;
// 这里如果返回true的话,touch事件将被拦截
// 拦截后 PopupWindow的onTouchEvent不被调用,这样点击外部区域无法dismiss
}
});

// 如果不设置PopupWindow的背景,无论是点击外部区域还是Back键都无法dismiss弹框
// 我觉得这里是API的一个bug
popupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.theme_dark_blue_bg));

// 设置好参数之后再show
//popupWindow.showAsDropDown(view);
}


}

1

demo连接:https://git.oschina.net/chang1286080091/PT-3280CInAndroid