您的位置:首页 > 移动开发 > Android开发

从音乐播放器谈Service

2017-01-06 16:01 323 查看
Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。



1. startedService

被开启的service通过其他组件调用 startService()被创建。

这种service可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它。

当service被停止时,系统会销毁它。

2.boundService

被绑定的service是当其他组件(一个客户)调用bindService()来创建的。

客户可以通过一个IBinder接口和service进行通信。

客户可以通过 unbindService()方法来关闭这种连接。

 

 

注意:

  一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。

1.Service与Activity之间可以相互调用(bindService,拿到一个binder实例任意调用)

2.如果采用bindService Service实例生命周期与Activity绑定到一起了,如果Activity销毁,Service也会销毁,那么不能做到后台播放

startService(Service实例与启动者的生命周期无关,除非调用stopService方法而消亡)

bindService(Service实例与启动者的生命周期关联,用户手动调用unbindService或者Activity消亡会跟着消亡)

两种方式各有千秋,结合起来可以实现灵活控制

生命周期

service整体的生命时间是从onCreate()被调用开始,到onDestroy()方法返回为止。和activity一样,service在onCreate()中进行它的初始化工作,在onDestroy()中释放残留的资源。

比如,一个音乐播放service可以在onCreate()中创建播放音乐的线程,在onDestory()中停止这个线程。

onCreate() 和 onDestroy()会被所有的service调用,不论service是通过startService()还是bindService()建立。

BindService:

当绑定service和所有客户端解除绑定之后,Android系统将会销毁它,(除非它同时被onStartCommand()方法开启)。

因此,如果你的service是一个纯粹的绑定service,那么你不需要管理它的生命周期。然而,如果你选择实现onStartCommand()回调方法,那么你必须显式地停止service,因为service此时被看做是开启的。这种情况下,service会一直运行到它自己调用stopSelf()或另一个组件调用stopService(),不论它是否和客户端绑定。 另外,如果你的service被开启并且接受绑定,那么当系统调用你的onUnbind()方法时,如果你想要在下次客户端绑定的时候接受一个onRebind()的调用(而不是调用onBind()),你可以选择在onUnbind()中返回true。onRebind()的返回值为void,但是客户端仍然在它的 onServiceConnected()回调方法中得到 IBinder 对象。



简单的音乐播放器代码:

public class MainActivity extends Activity {

private Button mPlayBtn;

private Button mStopBtn;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mPlayBtn = (Button) findViewById(R.id.play_pause);

mPlayBtn.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// Started

Intent intent = new Intent();

intent.putExtra(“command”, “play”);

intent.setClass(MainActivity.this, MusicService.class);

startService(intent);

}

});

mStopBtn = (Button) findViewById(R.id.stop_play);

mStopBtn.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// Stop

stopService(new Intent(MainActivity.this, MusicService.class));

}

});

findViewById(R.id.next).setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

//切换下一首歌曲

Intent intent = new Intent();

intent.putExtra(“command”, “next”);

intent.setClass(MainActivity.this, MusicService.class);

startService(intent);

}

});

}

}

Service代码:

package com.example.lesson18_service_start;

import java.util.ArrayList;

import java.util.List;

import android.app.PendingIntent;

import android.app.Service;

import android.content.Intent;

import android.media.MediaPlayer;

import android.os.IBinder;

import android.support.v4.app.NotificationCompat;

import android.util.Log;

import android.widget.RemoteViews;

public class MusicService extends Service {

MediaPlayer mediaPlayer;

List<Integer> songList = new ArrayList<>();
List<String> songNameList = new ArrayList<>();
int playIndex;// 当前播放歌曲的下标

@Override
public void onCreate() {// Service实例被创建
super.onCreate();
Log.i("at22", "onCreate");
// 歌曲的资源集合
songList.add(R.raw.abc);
songList.add(R.raw.areyouok);
songList.add(R.raw.zxmzf);
// 歌曲的名字
songNameList.add("abc");
songNameList.add("areyouok");
songNameList.add("zxmzf");

mediaPlayer = MediaPlayer.create(this, songList.get(playIndex));

// 第一次播放的时候更新通知栏的歌曲名字
updateNotification();

}
/**
* 更新通知栏
*/
private void updateNotification() {
//创建能兼容v7以上的通知栏构建者对象
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this);
// 通知栏三个必须的属性需要设置
builder.setSmallIcon(R.drawable.ic_launcher);
// builder.setContentText("abc");//自定义通知视图可以不写
// builder.setContentTitle("abc title");//自定义通知视图可以不写
//创建通知栏中自定义视图的类
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.notification_layout);
//获取当前的歌曲名字
String songName = songNameList.get(playIndex);
// 更新RemoteView中的文本内容
views.setTextViewText(R.id.song, songName);

Intent intent = new Intent();//下一首的歌曲
intent.putExtra("command", "next");
intent.setClass(this, MusicService.class);
Pendin
4000
gIntent pendingIntent = PendingIntent.getService(this, 1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 给RemoteView中的某个视图这是点击处理
views.setOnClickPendingIntent(R.id.next, pendingIntent);//第一个参数是下一首button视图的id
// 将自定义视图设置到通知栏中去
builder.setContent(views);
//启动一个通知与当前的服务“命运”关联
startForeground(111, builder.build());
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String command = intent.getStringExtra("command");

if ("play".equals(command)) {
playOrPause();
} else if ("next".equals(command)) {
playNext();
}
Log.i("at22", "onStartCommand" + command);
return super.onStartCommand(intent, flags, startId);
}

private void playNext() {
if (mediaPlayer != null) {// 释放播放器
mediaPlayer.stop();
mediaPlayer.release();
}
playIndex++;
if (playIndex >= songList.size()) {// 切换下一首歌曲
playIndex = 0;
}

int songRawId = songList.get(playIndex);// 歌曲的资源id
mediaPlayer = MediaPlayer.create(this, songRawId);
mediaPlayer.start();
// 有歌曲名变化时通知栏更新
updateNotification();
}

private void playOrPause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {//如果正在播放就暂停
mediaPlayer.pause();//暂停
} else {
mediaPlayer.start();//播放
}
}

@Override
public void onDestroy() {// Service实例被销毁
super.onDestroy();
Log.i("at22", "onDestroy");
}

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}


}

注意。由于Service是四大组建:一定要在清单文件中声明:

android:name=”.MusicService”



音乐播放器源代码:代码链接

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息