Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务并与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。
应使用服务还是线程?
服务是一种即使用户未与应用交互,但它仍可以在后台运行的组件。 因此,应仅在必要时才创建服务。如果您确实要使用服务,则默认情况下,它仍会在应用的主线程中运行,因此,如果服务执行的是密集型或阻止性操作(例如 MP3 播放或联网),则仍应在服务内创建新线程。
如需在主线程外部执行工作,不过只是在用户正在与应用交互时才有此需要,则应创建新线程而非服务。 例如,如果只是想在 Activity 运行的同时播放一些音乐,则可在 onCreate() 中创建线程,在 onStart() 中启动线程,然后在 onStop() 中停止线程。还可以考虑使用 AsyncTask 或 HandlerThread,而非传统的 Thread 类。
Service的种类
- 按运行类型分:
类别 | 区别 | 应用 |
---|---|---|
前台服务 | 会在通知栏显示onGoing的 Notification | 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。 |
后台服务 | 默认的服务即为后台服务,即不会在通知一栏显示 onGoing的 Notification。 | 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。 |
- 按使用方式分:
类别 | 区别 |
---|---|
startService启动的服务 | 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService。 |
bindService启动的服务 | 方法启动的服务要进行通信。停止服务使用unbindService。 |
同时使用startService、bindService 启动的服务 | 停止服务应同时使用stopService与unbindService。 |
使用service
- 使用startService启动服务
1.定义一个类继承service
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
return Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
}
onstartCommad方法返回一个int类型用来定义服务在被android系统终止之后的重启方式。最常用的三种常量返回值
2.在Manifest.xml文件中配置该Service
<service
android:name="MyService"
android:icon="@drawable/icon"
android:label="@string/service_name"
>
</service>
3.使用Context的startService(Intent)方法启动该Service
Intent intent = new Intent(this, MyService.class);
startService(intent);
4.不再使用时,调用stopService(Intent)方法停止该服务
.
使用这种方式创建启动服务的生命周期如下图:
注意:
1.如果服务已经开启,不会重复的执行onCreate(),而是会调用onStartCommand()。
2.服务停止的时候调用 onDestory()。服务只会被停止一次。
- 使用bindService方式启动服务
如果您的服务仅供本地应用使用,不需要跨进程工作,则可以实现自有 Binder 类,让您的客户端通过该类直接访问服务中的公共方法。
注:此方法只有在客户端和服务位于同一应用和进程内这一最常见的情况下方才有效。 例如,对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,此方法非常有效。
具体的创建服务的方法:
① 在服务中,创建一个可满足下列任一要求的 Binder 实例:
- 包含客户端可调用的公共方法
- 返回当前 Service实例,其中包含客户端可调用的公共方法
- 返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法
③ 在客户端中,从 [onServiceConnected()](https://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回调方法接收 Binder,并使用提供的方法调用绑定服务。
例如,以下这个服务可让客户端通过 Binder 实现访问服务中的方法:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
//Binder中包含返回该实例的方法
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService
//so clients can call public methods
return LocalService.this;
}
}
// onBind()回调方法返回此 Binder实例。
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
LocalBinder 为客户端提供 getService() 方法,以检索 LocalService 的当前实例。这样,客户端便可调用服务中的公共方法。 例如,客户端可调用服务中的 getRandomNumber()。
点击按钮时,以下这个 Activity 会绑定到 LocalService 并调用 getRandomNumber():
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService,建议在onstart方法中进行绑定
Intent intent = new Intent(this, LocalService.class);
//利用bindService(Intent, ServiceConnection, int)方法启动该Service
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service,建议在onstop方法中进行解绑
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang,
//then this request should occur in a separate thread
//to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder
//and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
特点:bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。绑定者可以调用服务里面的方法。
使用这种方式创建启动服务的生命周期如下图:
Service 元素的常见属性
属性 | 描述 |
---|---|
android:name | 服务类名 |
android:label | 服务的名字,如果此项不设置,那么默认显示的服务名则为类名 |
android:icon | 服务的图标 |
android:permission | 申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务 |
android:process | 表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字 |
android:enabled | 如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false |
android:exported | 表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false |
IntentService
IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。
另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
那么,用IntentService有什么好处呢?首先,我们省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service
下面来写一个Demo来模拟耗时操作在IntentService中的运行过程
自定义intentService
public class MyIntentService extends IntentService {
public static final String REUSLT = "reuslt";
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
String msg = intent.getStringExtra(MainActivity.COM_KEVINWANGY_TESTINTENTSERVICE_MSG);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
msg = "get result \"" + msg + "_result\" at "
+ android.text.format.DateFormat.format("dd/MM/yy h:mm:ss aa", System.currentTimeMillis());
Log.i("onHandleIntent", msg);
Intent resultIntent = new Intent();
resultIntent.setAction(MainActivity.ResultReceiver.RESULT_ACTION);
resultIntent.putExtra(REUSLT, msg);
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); //Service本身就是Context
localBroadcastManager.sendBroadcast(resultIntent);
}
}
定义MainActiviy , 其中包含一个BroadCastReceiver
public class MainActivity extends AppCompatActivity {
public static final String COM_KEVINWANGY_TESTINTENTSERVICE_MSG = "com.kevinwangy.testintentservice.msg";
private Button mButton;
private TextView mStart_text;
private TextView mFinish_text;
private EditText mEditText;
private String mStart_msg;
private ResultReceiver mResultReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final StringBuilder stringBuilder = new StringBuilder();
mStart_text = (TextView)findViewById(R.id.start_text);
mFinish_text = (TextView)findViewById(R.id.finish_text);
mEditText = (EditText)findViewById(R.id.input_edit);
mButton = (Button)findViewById(R.id.input_btn);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mStart_msg = mEditText.getText().toString();
stringBuilder.append("send message \"" + mStart_msg + "\" at "
+ android.text.format.DateFormat.format("dd/MM/yy h:mm:ss aa", System.currentTimeMillis()) + "\n");
mStart_text.setText(stringBuilder.toString());
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
intent.putExtra(COM_KEVINWANGY_TESTINTENTSERVICE_MSG, mStart_msg);
startService(intent);
}
});
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
}
public class ResultReceiver extends BroadcastReceiver {
}
}
ResultReceiver 的定义如下
public class ResultReceiver extends BroadcastReceiver {
public static final String RESULT_ACTION = "com.kevinwang.testintentservice.resultReceiver";
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && TextUtils.equals(intent.getAction(), RESULT_ACTION)) {
String result = intent.getStringExtra(MyIntentService.REUSLT);
Log.i("onReceive", result);
Log.i("onReceive", "context is " + context.toString());
mFinish_text.setText(result);
}
}
}
在onstart中注册BroadCastReceiver
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ResultReceiver.RESULT_ACTION);
mResultReceiver = new ResultReceiver();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(mResultReceiver, filter);
}
在onstop中解除注册
protected void onStop() {
super.onStop();
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.unregisterReceiver(mResultReceiver);
}
在androidManifest中声明
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".MyIntentService"/>
关于service、intentService、thread和AsyncTask的对比
参考文档及博客服务,绑定服务,Service那点事儿
网友评论