目录
1. Service介绍
1.1 Service是什么,有什么作用
2. Service生命周期
3. 自定义Service例子
3.1 观察Service生命周期
3.2 绑定Service例子
3.3 startService 与 bindService 的区别
4. IntentService
4.1 IntentService是什么
4.2 IntentService与Service的区别
4.3 IntentService例子Demo
1. Service介绍
Android 四大组件之Service(中译:服务)学习。
1.1 Service是什么,有什么作用
Service(中译:服务)是一个组件,用于在后台执行长时间运行的操作,如播放音乐、处理网络事务、交互内容提供者等。Service没有任何UI界面,所以不需要与用户交互,而且即使应用程序被破坏,它也能正常工作。
2. Service生命周期
Service有两种形式,分别是Start(启动)和Bound(绑定):
左边是Start Service;右边为Bound Service
Start(启动):当app组件(如Activity)通过调用startService()来启动服务,服务一旦启动,就可以在后台无限期运行,即使启动它的组件(如Activity)被销毁。可以通过调用stopService()方法来停止服务,而且服务本身可以通过调用stopSelf()方法来自行停止。
Bounded(绑定):当app组件通过调用bindService()方法绑定到服务时,服务将被绑定。绑定服务提供了一个client-server interface(客户机-服务器接口),该接口允许组件与服务交互、发送请求、获取结果。在所有客户端解除服务绑定之前,无法停止服务。
public class ExampleService extends Service {
int startMode; //指示在服务被终止时如何行为
IBinder binder; //用于绑定客户的接口
boolean allowRebind; //指示是否应该使用onRebind()
/**
* 在最初创建服务时(在调用onStartCommand()或onBind()之前),系统将调用此方法以执行一次性设置过程。
* 如果服务已经在运行,则不会调用此方法。
*/
@Override
public void onCreate() {
//正在创建服务
}
/**
* 当另一个组件(例如活动)请求启动服务时,系统通过调用startService()来调用此方法。
* 执行此方法时,服务将启动并可以无限期在后台运行。
* 如果执行此操作,则 必须 通过调用stopSelf()或stopService()在服务完成后停止该服务。如果只想提供绑定,则不需要实现此方法。
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//调用startService(),服务正在启动
return mStartMode;
}
/**
* 在call bindService()方法时调用。在此方法的实现中,必须提供一个接口,客户端可以通过返回IBinder使用该接口与服务进行通信。
* 当你实现绑定时,必须始终实现此方法。但是,如果不允许绑定,则应返回null。
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
//客户端使用bindService()来绑定到服务
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
//所有客户端都使用unbindService()来解除绑定
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
//重新绑定,指调用onUnbind()之后,客户端使用bindService()重新绑定到服务
}
/**
* 当服务不再使用并被销毁时,系统将调用此方法,所以这是服务收到的最后一个呼叫。
* 您的服务应实现此目的,以清理所有资源,例如线程,注册的侦听器或接收器。
*/
@Override
public void onDestroy() {
//服务不再使用,正在被销毁
}
}
3. 自定义Service例子
3.1 观察Service生命周期
startService 的周期为:开启 -> onCreate -> onStartCommand ,销毁 -> onDestry
简单的创建一个Service,然后启动它-然后销毁它,利用Toast显示状态,效果如下所示:
start创建服务,stop停止服务
1. 创建MyService服务,添加Toast用于显示Service状态
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service onCreate", Toast.LENGTH_SHORT).show();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service onDestroy", Toast.LENGTH_SHORT).show();
}
}
2. 在AndroidManifest签单文件中定义声明我们刚刚创建的MyService。(当然这一步可以让Android Studio来帮我们完成)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
//声明我们的服务
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
关于 Service 在清单文件中的一些参数说明:
1. android: name:对应 Service 类名,必须填写。
2. android: enabled:是否可以被系统实例化,默认为 true。
3.android: exported:代表是否能被其他应用所调用,如果将其设置为 false,则确保服务仅适用于您的应用。其默认值取决于定义的 Service 是否设置了 intent-filter,如果有 intent-filter,默认值为 true,否则为 false。为 false 的情况下,即使有 intent-filter 匹配,也无法打开,即无法被其他应用隐式调用。
3. 在我们的app组件-MainActivity.java文件中进行 Service 的操作,(启动服务,停止服务)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startBtn = findViewById(R.id.start_service_btn);
startBtn.setOnClickListener(this);
Button stopBtn = findViewById(R.id.stop_service_btn);
stopBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service_btn:
//启动服务
Intent intent = new Intent(this, MyService.class);
startService(intent);
break;
case R.id.stop_service_btn:
//停止服务
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
break;
default:
break;
}
}
}
3.2 绑定Service例子
相对比与Start Service,bound service会相对复杂些,见下例所示:
具体代码如下:
public class MyBoundService extends Service {
private final IBinder mBinder = new MyBinder();
private final Random mGenerator = new Random();
public MyBoundService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class MyBinder extends Binder {
MyBoundService getService() {
//返回MyBoundService的实例
return MyBoundService.this;
}
}
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BoundServiceTestActivity extends AppCompatActivity {
private MyBoundService boundService;
private boolean isBoundService = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bound_service_test);
Button getRandomBtn = findViewById(R.id.get_number_btn);
getRandomBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isBoundService) {
Toast.makeText(BoundServiceTestActivity.this,
"random Number is: " + boundService.getRandomNumber(),
Toast.LENGTH_SHORT)
.show();
}
}
});
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyBoundService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (isBoundService) {
unbindService(serviceConnection);
isBoundService = false;
}
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyBoundService.MyBinder binder = (MyBoundService.MyBinder) service;
boundService = binder.getService();
isBoundService = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBoundService = false;
}
};
}
3.3 startService 与 bindService 的区别
从二者的生命周期上看:
startService 开启的 Service 的生命周期不与开启它的 Activity 的生命周期相关联,即使开启它的 Activity 销毁了,该 Service 还会一直运行,直到调用 stopService() 或 Service 自身调用 stopSelf(),该 Service 才会被销毁。
bindService 开启的 Service 的生命周期与开启它的 Activity 的生命周期相关联,如果开启它的 Activity 被销毁了,那该 Service 也就会被销毁。
4. IntentService
4.1 IntentService是什么
IntentService是Service的子类,继承于Service类,用于处理需要异步请求的任务。用户通过调用Context.StartService(Intent)发送请求,服务根据需要启动,使用工作线程依次处理每个Intent,并在处理完所有工作后自身停止服务。
使用时,扩展IntentService并实现onHandleIntent(android.content.Intent)。IntentService接收Intent,启动工作线程,并在适当时机停止服务。
所有的请求都在同一个工作线程上处理,一次处理一个请求,所以处理完所以的请求可能会花费很长的时间,但由于IntentService是另外创建的线程来工作,所以保证不会阻止App的主线程。
4.2 IntentService与Service的区别
从何时使用,触发方法,运行环境,何时停止四个方面分析。
1、何时使用:
Service用于没有UI工作的任务,但不能执行长任务(长时间的任务),如果需要Service来执行长时间的任务,则必须手动开启一个线程来执行该Service。
IntentService可用于执行不与主线程沟通的长任务。
2、触发方法:
Service通过调用 startService() 方法来触发。
而IntentService通过Intent来触发,开启一个新的工作线程,并在线程上调用 onHandleIntent() 方法。
3、运行环境:
Service 在App主线程上运行,没有与用户交互,即在后台运行,如果执行长时间的请求任务会阻止主线程工作。
IntentService在自己单独开启的工作线程上运行,即使执行长时间的请求任务也不会阻止主线程工作。
4、何时停止
如果执行了Service,我们是有责任在其请求任务完成后关闭服务,通过调用 stopSelf() 或 stopService()来结束服务。
IntentService会在执行完所有的请求任务后自行关闭服务,所以我们不必额外调用 stopSelf() 去关闭它。
4.3 IntentService例子Demo
通过Android Studio来创建我们的MyIntentService。
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public static final String DOWNLOAD_ACTION = "DOWNLOAD_ACTION";
public static final String READ_ACTION = "READ_ACTION";
public static final String TEST_AUTHOR = "TEST_AUTHOR";
public MyIntentService() {
super("MyIntentService");
}
/**
* 进行一些耗时操作
* @param intent 通过startService(Intent intent)方法传入
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.e(TAG, "onHandleIntent: ");
if (intent != null) {
final String action = intent.getAction();
String author = intent.getExtras().getString(TEST_AUTHOR);
//模拟下载动作
if (DOWNLOAD_ACTION.equals(action)) {
for (int i = 0; i < 5; i++) {
try {
//线程等待1s,模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, author + " " + action + " " + i);
}
}
//模拟读操作
if (READ_ACTION.equals(action)) {
for (int i = 0; i < 5; i++) {
try {
//线程等待2s,模拟耗时操作
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, author + " " + action + " " + i);
}
}
}
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onCreate: ");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
Log.e(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
super.onStart(intent, startId);
Log.e(TAG, "onStart: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: ");
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
}
}
如果你是手动创建IntentService的,得在AndroidManifest.xml文件中注册该IntentService,如果通过Android Studio创建则免去这一步了。
<service
android:name=".intentservice.MyIntentService"
android:exported="false">
</service>
在主线程中通过调用 startService(Intent) 方法,发送请求给 Service。
public class IntentServiceActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
//模拟 Jere 做下载动作
Intent intent = new Intent(this, MyIntentService.class);
intent.setAction(MyIntentService.DOWNLOAD_ACTION);
intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere");
startService(intent);
//模拟 James 做读取动作
Intent jamesIntent = new Intent(this, MyIntentService.class);
jamesIntent.setAction(MyIntentService.READ_ACTION);
jamesIntent.putExtra(MyIntentService.TEST_AUTHOR, "James");
startService(jamesIntent);
}
}
打印 Log 信息如下所示:
IntentService 的执行顺序是: onCreate() -> onStartCommand() -> onStart() -> onHandleIntent() -> ··· 执行完所有请求 ··· -> onDestroy()。
END~