标签:
“Service”意思即“服务”的意思,像 Windows 上面的服务一样,服务是在后台上运行,承担着静悄悄的不为人所注意的工作。Service运行在后台,它是不可见的、无界面的程序。Service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity,这个时候程序要在后台继续播放;比如检测SD卡上文件的变化;再或者在后台记录用户的地理信息位置的改变;或者启动一个服务来运行并一直监听某种动作等等。
Local Service 用于应用程序内部。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
启动service有两种方法:
1)、 Context.startService()
调用者与服务之间没有关联,即使调用者退出,服务仍可运行
2)、 Context.bindService()
调用者与服务绑定在一起,调用者一旦退出,服务也就终止
被启动的服务是由其它组件调用startService()方法而启动的,该方法会导致被启动服务的生命周期方法onStartCommand()被回调。当服务是被启动状态后,其生命周期与启动它的组件无关,即使启动服务的组件(Activity,BroadcastReceiver)已经被销毁,该服务还可以在后台无限期运行。除非调用stopSelf()或stopService()来停止该服务。
绑定服务是允许其它应用程序绑定并且与之交互的Service的实现类。为了提供绑定,必须实现onBind()回调方法。该方法返回IBinder对象,它定义了服务类与Activity交互的程序接口。
Activity通过bindService()方法绑定到服务类,同时Activity必须提供ServiceConnection接口的实现类,它监视Activity与服务类之间的连接。在重写ServiceConnection接口的onServiceConnected()方法时,实现了将服务类顺利赋值到了Activity中,实现了在Activity中使用该服务类并执行其中的方法。
onStartCommand()方法有三种返回值:
【备注:】
以上三种情况,可以理解为发生车祸后的人:
Remote Service 用于android系统内部的应用程序之间。可以定义接口并把接口暴露出来,以便其他应用进行操作。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
【详细说明:】
【详细说明:】
【备注:】
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
private boolean isStop = true;
@Nullable
@Override
public IBinderonBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
//当音乐播放完成时调用
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
//播放完成之后发送广播给Activity
Intent intent = new Intent("play_completion");
sendBroadcast(intent);
}
});
}
// AlertDialog.Builder b = newAlertDialog.Builder(this);
}
@Override
public int onStartCommand(Intent intent, intflags, int startId){
//获得Activity传递过来的state
int state= intent.getIntExtra("state", 0);
switch (state){
//开始播放
case 0:
if (isStop) {
preparePlayMusic();
isStop = false;
} else if (mediaPlayer != null &&!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
break;
//暂停播放
case 1:
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
break;
//停止播放
case 2:
if (mediaPlayer != null) {
mediaPlayer.stop();
isStop = true;
}
break;
}
//START_STICKY,被系统回收之后,服务重启,同时intent为null
//START_NOT_STICKY,被系统回收之后,服务不会重启
//START_REDELIVER_INTENT,被系统回收之后,服务重启,同时intent还为之前的intent
return this.START_NOT_STICKY;
}
private void preparePlayMusic() {
try {
//重置MediaPlayer
mediaPlayer.reset();
//设置播放数据源
mediaPlayer.setDataSource(Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator +
"xiami" + File.separator + "audios" + File.separator + "被动.mp3"
);
//准备播放
mediaPlayer.prepare();
//开始播放
mediaPlayer.start();
//设置是否循环播放
mediaPlayer.setLooping(false);
} catch (IOExceptione) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
public class MainActivity extends AppCompatActivity {
private Intent intent;
private MyReceiver myReceiver;
private IntentFilter intentFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, MusicService.class);
myReceiver = new MyReceiver();
intentFilter = new IntentFilter();
intentFilter.addAction("play_completion");
}
public void start(View view) {
intent.putExtra("state", 0);
startService(intent);
}
public void pause(View view) {
intent.putExtra("state", 1);
startService(intent);
}
public void stop(View view) {
intent.putExtra("state", 2);
startService(intent);
}
@Override
protected void onStart() {
super.onStart();
registerReceiver(myReceiver,intentFilter);
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(myReceiver);
}
}
不管是何种Service,它默认都是在应用程序的主线程(亦即UI线程)中运行的。所以,如果你的Service将要运行非常耗时或者可能被阻塞的操作时,你的应用程序将会被挂起,甚至会出现ANR错误。为了避免这一问题,你应该在Service中重新启动一个新的线程来进行这些操作。现有两种方法大家参考:
① 直接在Service的onStartCommand()方法中新建一个线程来执行;
② Android SDK 中为我们提供了一个现成的Service类来实现这个功能,它就是IntentService,它主要负责以下几个方面:
IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的workerthread中处理,不会阻塞应用程序的主线程。
这里就给我们提供了一个思路,如果有耗时的操作可以在Service里面开启新线程,也可以使用IntentService来处理耗时操作。 但你若是想在Service中让多个线程并发的话,就得使用第一种方法,在Service内部起多个线程。
2.MusicService核心代码:
public class MyService extends Service {
private MediaPlayer mediaPlayer;
private boolean isStop = true;
private File[] files;
private int currentPosition = 0;
//创建服务时调用
@Override
public void onCreate() {
super.onCreate();
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
// preparePlayMusicx();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
currentPosition++;
preparePlayMusicx();
isStop = false;
}
});
}
Log.d("lenve", "onCreate:");
}
private void preparePlayMusicx() {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(files[currentPosition].getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOExceptione) {
e.printStackTrace();
}
}
//创建时调用
@Nullable
@Override
public IBinderonBind(Intent intent) {
files =((MusicFiles) intent.getSerializableExtra("files")).getFiles();
Log.d("lenve", "onBind:");
return new MyBinder();
}
//解除绑定时调用
@Override
public boolean onUnbind(Intent intent) {
Log.d("lenve", "onUnbind:");
return super.onUnbind(intent);
}
//解除绑定时调用
@Override
public void onDestroy() {
super.onDestroy();
Log.d("lenve", "onDestroy:");
}
//自定义一个类继承自Binder
class MyBinderextends Binder {
//在该类中定义一个方法,该方法返回当前Service的实例
public MyServicegetService() {
//返回当前Service的实例
return MyService.this;
}
}
public void play() {
if (isStop) {
preparePlayMusicx();
isStop = false;
} else if (mediaPlayer != null &&!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
isStop = true;
}
}
}
3.Activity核心代码:
public class MainActivity extends AppCompatActivity {
private Intent intent;
private ServiceConnection conn;
private MyService myService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取音乐文件列表
File[] listFiles = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "xiami"+ File.separator + "audios").listFiles(new FileFilter(){
//过滤出所有的mp3文件
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".mp3")) {
return true;
}
return false;
}
});
intent = new Intent(this, MyService.class);
intent.putExtra("files", new MusicFiles(listFiles));
//当Activity和Service产生连接之后触发该方法
//Activity和Service连接断开后调用该方法
conn = new ServiceConnection() {
//当Activity和Service产生连接之后触发该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.MyBinder) service).getService();
Log.d("lenve", "onServiceConnected:");
}
//Activity和Service连接断开后调用该方法
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("lenve", "onServiceDisconnected:");
}
};
//绑定服务,返回值表示绑定是否成功
boolean flag = bindService(intent, conn,Service.BIND_AUTO_CREATE);
}
public void bindService(View view) {
boolean flag = bindService(intent, conn,Service.BIND_AUTO_CREATE);
}
public void unbindService(View view) {
unbindService(conn);
}
public void play(View view) {
myService.play();
}
public void pause(View view) {
myService.pause();
}
public void stop(View view) {
myService.stop();
}
}
Android操作系统尝试尽可能长时间保持应用的进程,但当可用内存很低时要移走一部分进程。哪些程序可以运行,哪些要被销毁?答案是:重要级别低的进程可能被淘汰。
按照重要性排列,一共可以分成5级:
用户此时需要处理和显示的进程。符合下列条件任何一个,这个进程就被认为是前台运行进程。
销毁前台运行进程是系统万不得已的、最后的选择——当内存不够系统继续运行下去时,杀掉一些前台进程来保证能够响应用户的需求。
一个可用进程没有任何前台组件,但它仍然可以影响到用户的界面。下面情况发生时,可以称该进程为可用进程。
它是一个非前台的activity,但对用户仍然可用(onPause()方法已经被调用)。例如:前台的activity是一个允许上一个activity可见的对话框。也就是说当前activity中是一个对话框,对话框之外的地方能看到前一个activity的界面。
服务进程是一个通过调用startService()方法启动的服务,并且不属于前两种情况。尽管服务进程没有直接被用户看到,但他们确实是用户所关心的,比如后台播放音乐或网络下载数据,所以系统保证他们的运行。
一个后台进程就是非当前正在运行的activity(activity的onStop()方法已经被调用),他们不会对用户体验造成直接的影响,当没有足够内存来运行前台可见程序时,他们将会被终止。
通常,后台进程会有很多个在运行,LRU最近使用程序列表来保证经常运行的activity能最后一个被终止。
一个空线程没有运行任何可用应用程序,保留他们的唯一原因是为了设立一个缓存机制,来加快组件启动的时间。系统经常杀死这些内存来平衡系统的整个系统的资源,进程缓存和基本核心缓存之间的资源。、
1.Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序
2.Service与Activity的区别:
>Service一直在后台运行,它没有用户界面,所以绝不会到前台来
>它完全具有自己的生命周期
3.应用场景:
>音乐播放器、后台下载等
4.Activity与Service的选择标准
>如果在运行时需要向用户呈现界面,或该程序需要与用户交互,就需要使用Activity
>否则就应该考虑使用Service
5.Service分类
>本地服务(在应用内)
>远程服务(在另一个应用内)
6.开发者开发Service的步骤与开发Activity的步骤很相似:
A.创建一个类,继承Service
B.重写Service类中的相关生命周期方法
C.别忘记在清单文件中进行注册
7.Service与Activity的相似处:
>都是从Context派生出来,因此都可以调用Context里定义的如getResources()、getContentResolver()等方法
8.服务的启动方式:
>服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务
>两种启动方式的区别:
startService()启动服务,启动者与服务之间没有关联,即使访问者退出了,服务仍然运行
bindService()启动服务,启动者与服务之间绑定在了一起,启动者退出,则服务也就终止--"不求同生,但求同死"
9.服务的结束方式:
>采用Context.startService()启动的服务,只能调用Context.stopService()终止服务,
服务结束会调用onDestroy()方法启动服务
>采用bindService()启动的服务,随着访问者的退出而自动退出
10.注意:
>startService()启动的服务,启动者退出时,服务不会停止,除非调用stopService()
>bindService()启动服务,启动者退出时,服务也应该随之终止
>service虽然在后台运行,也不要在其中执行耗时的任务(如网络下载),请在相应的方法中开启一个线程来处理
标签:
原文地址:http://blog.csdn.net/qq_33544860/article/details/51188224