前言:
Android四大组件,Activity,Service,BroadcastReceiver和ContentProvider。最近在工作中遇到很多网络处理操作都用线程来处理,想想好像Service就是用来进行这类操作的,这两者的区别和使用场合有点模糊了,最近主要研究了service并进行总结,以备后用。
一.Service 定义
1.根据官网对于Service的定义翻译为中文:
Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。
2.加深对Service的理解,可以看下这段描述:
(1).A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
(2).A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
(个人英语一般,但总感觉这段描述的英文好像有问题)
可以译为:
(1).Service并不是一个单独的进程,Service对象如果不明确指明,不意味着运行在它自身的进程中,它运行在Application的系统进程中,是进程的一部分。
(2).Service不是一个线程,不意味着可以在主线程之外执行其它工作(避免应用ANR)。
关于第二点需要重点说明一下:网上的文章很多都把耗时的操作直接放在Service的onStart方法中,而且没有强调这样会出现Application Not Responding!Service不是一个线程,不能直接处理耗时的操作,如果非要在Service中进行耗时处理,就必须开启一个单独的线程来处理或者采用IntentService来实现。
关于IntentService,后面会加以总结。
二. 与Activity的区别
1.不能与用户交互,对用户透明。
2.不能自己启动。
3.当我们退出应用时,Service进程并没有结束,它仍然可以在系统后台运行。
Service有两种状态:“启动的”和“绑定”。就是当调用服务的startService()和bindService()之后出现的状态。可以简单理解为:”started”和“binded”。
三 Service的启动
有两种方式可以启用一个Service。
a、Context.startService()
使用这个方法时,service与启动者是没有关系的,只是单纯的启动service,若启动者退出了,service依旧在后台运行。(如音乐播放,即使退出了程序,音乐还在播放着)
b、Context.bindService()
使用此方法时,顾名思义,就是把启动者与service绑定在一起了,启动者退出,service也跟着停止。
四 Service的生命周期
服务启用的方式不同,生命周期也不一样.
1.startService()方式启用的Service:
onCreate()—>>onStart()—>>onDestroy();
2.bindService()方式启用的Service:
onCreate()—>>onBind()—>>onUnBind()—>>onDestroy();
两种方式下的Service生命周期如下图展示:
五 一个后台开启音乐的ServiceDemo
类似的Demo网上很多,随便改了一个,写在下面,仅供参考:
1.MusicService.java
继承Service类,必须重写onBind()方法。
Service类的业务处理,写在onCreate()方法内部。
注意:R.raw.ccnnian 要在Res文件夹下面创建raw文件夹,将ccnnian(匆匆那年.mp3)放进去,修改名字。
package com.elvis.musicService;
import com.example.servicedemo.R;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MusicService extends Service
{
//为日志工具设置标签
String tag = "MusicService";
//定义音乐播放器变量
MediaPlayer mPlayer;
//其他对象通过bindService方法通知该Service时该方法会被调用
@Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
Toast.makeText(this, "MusicService onBind() ",
Toast.LENGTH_LONG).show();
Log.i(tag,"MusicService onBind()");
mPlayer.start();
return null;
}
//其他对象通过unbindService方法通知该Service时该方法会被调用
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(this, "MusicService onUnbind() ",
Toast.LENGTH_LONG).show();
Log.i(tag, "MusicService onUnbind()");
mPlayer.stop();
return false;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
Toast.makeText(this, "MusicService onCreate() ",
Toast.LENGTH_LONG).show();
//创建一个音乐播放器
//mPlayer = MediaPlayer.create(getApplicationContext(),R.);
mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.ccnnian);
mPlayer.setLooping(true);
Log.i(tag, "MusicService onCreate()");
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
Toast.makeText(this, "MusicSevice onDestroy()"
, Toast.LENGTH_SHORT).show();
Log.e(tag, "MusicService onDestroy()");
mPlayer.stop();
super.onDestroy();
}
@Override
@Deprecated
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
Toast.makeText(this, "MusicSevice onStart()"
, Toast.LENGTH_SHORT).show();
Log.e(tag, "MusicSerice onStart()");
mPlayer.start();
super.onStart(intent, startId);
}
}
2.ServiceActivity.java
两种方式开启服务。注意Intent intent = new Intent(ServiceActivity.this,MusicService.class);
通过Intent对象实现Service启动。
package com.example.servicedemo;
import com.elvis.musicService.MusicService;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class ServiceActivity extends Activity {
//为日志工具设置标签
private static String tag = "MusicService";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service);
Toast.makeText(this, "ServiceActivity",
Toast.LENGTH_LONG).show();
Log.e(tag, "MusicServiceActivity");
initView();
}
//定义服务链接对象
final ServiceConnection conn = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
// TODO Auto-generated method stub
Toast.makeText(ServiceActivity.this, "MusicServiceActivity onServiceConnected"
,Toast.LENGTH_SHORT).show();
Log.e(tag, "MusicServiceActivity onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
Toast.makeText(ServiceActivity.this, "MusicServiceActivity onSeviceDisconnected"
, Toast.LENGTH_SHORT).show();
Log.e(tag, "MusicServiceActivity onSeviceDisconnected");
}
};
private void initView()
{
Button btnStart = (Button)findViewById(R.id.Button01);
Button btnStop = (Button)findViewById(R.id.Button02);
Button btnBind = (Button)findViewById(R.id.Button03);
Button btnUnbind = (Button)findViewById(R.id.Button04);
OnClickListener ocl = new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//显示指定, intent 所指的对象是 service
Intent intent = new Intent(ServiceActivity.this,MusicService.class);
switch(v.getId())
{
case R.id.Button01:
startService(intent);
break;
case R.id.Button02:
//停止服务
stopService(intent);
break;
case R.id.Button03:
//绑定服务
bindService(intent, conn, Context.BIND_AUTO_CREATE);
break;
case R.id.Button04:
//解绑服务
unbindService(conn);
break;
}
}
};
btnStart.setOnClickListener(ocl);
btnStop.setOnClickListener(ocl);
btnBind.setOnClickListener(ocl);
btnUnbind.setOnClickListener(ocl);
}
}
3.注册Service
在AndroidManifest.xml文件中,添加
<service android:name="com.elvis.musicService.MusicService"/>
到<application>标签内部。
六 总结
startService()方式开启的音乐,在程序退出时依然播放。
bindService()方式开启的音乐,程序退出时停止播放。