一. Service生命周期
- 官方说明图:
- startService启动方式生命周期
- 手动调用 startService 后,自动调用 onCreate() -> onStartCommand()
- 若一个 Service 被 startService 调用多次, onCreate 方法只会调用一次;
- 整个生命周期中, 只有 onStartCommand 会被多次调用, 其他只会调用一次;
- onStartCommand 调用次数 = startService 调用次数;
- onStartCommand 必须返回一个整数, 描述系统杀死服务后应该如何继续运行.
a. START_STICKY
如果Service所在的进程,在执行了onStartCommand方法后,被清理了,那么这个Service会被保留在已开始的状态,但是不保留传入的Intent ,随后系统会尝试重新创建此Service,由于服务状态保留在已开始状态,所以创建服务后一定会调用onStartCommand方法。如果在此期间没有任何启动命令被传递到service ,那么参数Intent将为null ,需要我们小心处理。==(重建服务&调用 onStartCommand, 不会再次传入上一个 intent , 而是用 null intent 来调 onStartCommand , 除非有启动服务的 intent 未发送完, 那么这些余下的 intent 会继续发送)==适用于媒体播放器, 他们不执行命令, 但需要一直运行并随时待命.
b. START_NOT_STICKY
如果Service所在的进程,在执行了onStartCommand方法后,被清理了,则系统不会重新启动此Service。当服务不再是必须的, 并且应用程序能够简单的重启那些未完成的工作时, 这是避免服务运行的最安全的选项.
c. START_REDELIVER_INTENT
如果Service所在的进程,在执行了onStartCommand方法后,被清理了,则结果和START_STICKY一样,也会重新创建此Service并调用onStartCommand方法。不同之处在于,如果是返回的是START_REDELIVER_INTENT ,则重新创建Service时onStartCommand方法会传入之前的intent
(重建服务& 用上一个已发送的 intent 去调用onStartCommand, 任何未发的 intent 也会依次送入)适用于需要立即恢复工作的活跃服务, 如下载文件.
d. START_STICKY_COMPATIBILITY
这个比较简单,是START_STICKY的兼容版本,但是不能保证被清理后onStartCommand方法一定会被重新调用 - 手动调用stopService, 关闭服务, 自动调用 onDestory()
- 手动调用 startService 后,自动调用 onCreate() -> onStartCommand()
- 绑定的方式启动服务
- 手动调用 bindService 后, onCreate() -> onBind()
- 手动调用 unbindService , onUnbind() -> onDestory()
- UML图解
二. 服务分类
1.具体分类
2.详情介绍
3.本地服务,无法和 Activity 通信
- LocalService
public class LocalService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
//启动Service之后,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑
//由于这里作Demo用,所以只打印一些语句
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: " );
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: "+intent.getStringExtra("key") );
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: " );
}
}
布局文件, 用于启动和停止服务 ```java <?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="按运行地点分类"/>
<Button
android:id="@+id/btn_service_test_local"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="本地服务,启动"
android:onClick="localstartListener"
/>
<Button
android:id="@+id/btn_service_test_localStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="本地服务,stop"
android:onClick="localStopListener"
/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="可通信的服务"/>
<Button
android:id="@+id/btn_service_test_bindStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动绑定"
android:onClick="bindstartListener"
/>
<Button
android:id="@+id/btn_service_test_bindService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调用服务里的方法"
android:onClick="bindServiceListener"
/>
<Button
android:id="@+id/btn_service_test_bindStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="解绑服务,stop"
android:onClick="bindStopListener"
/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="前台服务,两种方式都可以是前台服务"/>
<Button
android:id="@+id/btn_service_test_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start方式启动"
android:onClick="startListener"
/>
<Button
android:id="@+id/btn_service_test_startStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start方式停止"
android:onClick="startStopListener"
/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="后台服务, IntentService"/>
<Button
android:id="@+id/btn_service_test_intentStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动"
android:onClick="intentstartListener"
/>
</LinearLayout>
</ScrollView>
1. Activity, 调用方法
```java
package com.kiwilss.lxkj.fourassembly.service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.kiwilss.lxkj.fourassembly.R;
/**
* @author : Lss kiwilss
* @FileName: ServiceTestActivity
* @e-mail : kiwilss@163.com
* @time : 2019/4/16
* @desc : {DESCRIPTION}
*/
public class ServiceTestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service_test);
}
public void startListener(View view) {
Intent intent = new Intent(this, StartService.class);
intent.putExtra("key","start");
startService(intent);
}
public void startStopListener(View view) {
Intent intent = new Intent(this, StartService.class);
intent.putExtra("key","stop");
stopService(intent);
}
public void localstartListener(View view) {
Intent intent = new Intent(this, LocalService.class);
intent.putExtra("key","start");
startService(intent);
}
public void localStopListener(View view) {
Intent intent = new Intent(this, LocalService.class);
stopService(intent);
}
BindService.MyBinder myBinder;
//创建 serviceConnection 匿名类
private ServiceConnection mSc = new ServiceConnection(){
//重写onServiceConnected()方法和onServiceDisconnected()方法
//在Activity与Service建立关联和解除关联的时候调用
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//实例化Service的内部类myBinder
//通过向下转型得到了MyBinder的实例
Log.e("MMM", "onServiceConnected: " );
myBinder = (BindService.MyBinder) iBinder;
//调用服务里的方法
myBinder.serviceConnectActivity();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("MMM", "onServiceDisconnected: " );
}
};
public void bindstartListener(View view) {
//构建绑定服务的Intent对象
Intent bindIntent = new Intent(this, BindService.class);
bindIntent.putExtra("key","binder");
//调用bindService()方法,以此停止服务
bindService(bindIntent,mSc,BIND_AUTO_CREATE);
//参数说明
//第一个参数:Intent对象
//第二个参数:上面创建的Serviceconnection实例
//第三个参数:标志位
//这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service
//这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行
}
public void bindStopListener(View view) {
//调用unbindService()解绑服务
//参数是上面创建的Serviceconnection实例
unbindService(mSc);
}
public void bindServiceListener(View view) {
if (myBinder != null){
myBinder.serviceConnectActivity();
myBinder.getService().serviceConnectActivity();
myBinder.getService().serviceFun();
}
}
public void intentstartListener(View view) {
// 请求1
// Intent i = new Intent("cn.scu.finch");
// Bundle bundle = new Bundle();
// bundle.putString("taskName", "task1");
// i.putExtras(bundle);
// startService(i);
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra("taskName","task1");
startService(intent);
Intent intent2 = new Intent(this, MyIntentService.class);
intent2.putExtra("taskName","task2");
startService(intent2);
startService(intent);
// 请求2
// Intent i2 = new Intent("cn.scu.finch");
// Bundle bundle2 = new Bundle();
// bundle2.putString("taskName", "task2");
// i2.putExtras(bundle2);
// startService(i2);
//
// startService(i); //多次启动
}
}
- 启动服务:
public void localstartListener(View view) {
Intent intent = new Intent(this, LocalService.class);
intent.putExtra("key","start");
startService(intent);
}
停止服务:
public void localStopListener(View view) {
Intent intent = new Intent(this, LocalService.class);
stopService(intent);
}
清单文件注册
<service android:name=".service.LocalService"/>
服务属性介绍:
name 服务的类名
label Service的名字
icon Service的图标
permission 申明服务的权限(有提供了该权限的应用才能控制或连接服务)
process 表明该服务是否在另一个进程中运行(不设置默认本地服务, remote 设置成远程服务)
enabled 系统默认启动,true:Service 将会默认被系统启动;不设置则默认为false
exported 该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false- 测试结果
点击开启:
2019-04-17 18:10:10.621 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onCreate:
2019-04-17 18:10:10.621 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onStartCommand: start
点击关闭:
2019-04-17 18:10:12.880 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onDestroy:
4.可通信的服务,绑定方式开启
- BindService ```java package com.kiwilss.lxkj.fourassembly.service;
import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.support.annotation.Nullable; import android.util.Log;
import static com.kiwilss.lxkj.fourassembly.service.StartService.TAG;
/**
- @author : Lss kiwilss
- @FileName: BindService
- @e-mail : kiwilss@163.com
- @time : 2019/4/17
@desc : {DESCRIPTION}可通信的服务,即实现了Activity指挥Service干什么Service就去干什么的功能 */ public class BindService extends Service { //@androidx.annotation.Nullable
MyBinder myBinder = new MyBinder(); @Nullable @Override public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: " + intent.getStringExtra("key"));
return myBinder;
}
@Override public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: " );
}
@Override public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
@Override public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: " );
return super.onUnbind(intent);
}
@Override public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: " );
}
public void serviceFun(){
Log.e(TAG, "serviceFun: activity 调用服务里的方法" );
}
public void serviceConnectActivity(){
Log.e(TAG, "serviceConnectActivity: +++++++服务关联activity,并在activity中执行服务中的方法" );
} //新建一个子类继承 binder class MyBinder extends Binder{
public void serviceConnectActivity(){
Log.e(TAG, "serviceConnectActivity: *****+服务关联activity,并在activity中执行服务中的方法" );
}
public BindService getService(){
return BindService.this;
}
} } ```
- 布局界面和 Activity 同上
绑定启动:
public void bindstartListener(View view) {
//构建绑定服务的Intent对象
Intent bindIntent = new Intent(this, BindService.class);
bindIntent.putExtra("key","binder");
//调用bindService()方法,以此停止服务
bindService(bindIntent,mSc,BIND_AUTO_CREATE);
//参数说明
//第一个参数:Intent对象
//第二个参数:上面创建的Serviceconnection实例
//第三个参数:标志位
//这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service
//这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行
}
解除绑定:
public void bindStopListener(View view) {
//调用unbindService()解绑服务
//参数是上面创建的Serviceconnection实例
unbindService(mSc);
}
- 测试结果
启动绑定:
2019-04-17 18:16:43.319 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onCreate:
2019-04-17 18:16:43.319 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onBind: binder
2019-04-17 18:16:43.328 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onServiceConnected:
2019-04-17 18:16:43.329 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: serviceConnectActivity: *+服务关联activity,并在activity中执行服务中的方法
解除绑定:
2019-04-17 18:17:20.089 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onUnbind:
2019-04-17 18:17:20.089 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onDestroy:
5.前台服务,两种启动方式都可以
前台服务和后台服务的区别
- 前台Service在下拉通知栏有显示通知(如下图),但后台Service没有;
- 前台Service优先级较高,不会由于系统内存不足而被回收;后台Service优先级较低,当系统出现内存不足情况时,很有可能会被回收
Service:
package com.kiwilss.lxkj.fourassembly.service;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import com.kiwilss.lxkj.fourassembly.MainActivity;
import com.kiwilss.lxkj.fourassembly.R;
/**
* @author : Lss kiwilss
* @FileName: StartService
* @e-mail : kiwilss@163.com
* @time : 2019/4/16
* @desc : {DESCRIPTION}
*/
public class StartService extends Service {
public static final String TAG = "MMM";
//@androidx.annotation.Nullable
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: ");
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
//改造成前台服务
//添加下列代码将后台Service变成前台Service
//构建"点击通知后打开MainActivity"的Intent对象
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
//新建Builer对象
Notification.Builder builer = new Notification.Builder(this);
builer.setContentTitle("前台服务通知的标题");//设置通知的标题
builer.setContentText("前台服务通知的内容");//设置通知的内容
builer.setSmallIcon(R.mipmap.ic_launcher);//设置通知的图标
builer.setContentIntent(pendingIntent);//设置点击通知后的操作
//builer.setAutoCancel(true);//设置可取消
Notification notification = builer.getNotification();//将Builder对象转变成普通的notification
startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String key = intent.getStringExtra("key");
Log.e(TAG, "onStartCommand: " + key);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: ");
}
}
6.IntentService 后台服务
- 介绍
处理异步请求 & 实现多线程.
最常见的场景:离线下载
不符合多个数据同时请求的场景:所有的任务都在同一个Thread looper
里执行 - 使用
MyIntentService ```java package com.kiwilss.lxkj.fourassembly.service;
import android.app.IntentService; import android.content.Intent; import android.support.annotation.Nullable; import android.util.Log;
/**
- @author : Lss kiwilss
- @FileName: MyIntentService
- @e-mail : kiwilss@163.com
- @time : 2019/4/17
@desc : {DESCRIPTION} */ public class MyIntentService extends IntentService { private static final String TAG = “MMM”;
public MyIntentService(String name) {
super(name);
}
public MyIntentService(){
// 调用父类的构造函数
// 参数 = 工作线程的名字
super("myIntentService");
}
@Override public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: " );
}
@Override public int onStartCommand( @Nullable Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
@Override public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: " );
}
/**
- 复写onHandleIntent()方法
- 根据 Intent实现 耗时任务 操作
**/
@Override
protected void onHandleIntent( @Nullable Intent intent) {
// 根据 Intent的不同,进行不同的事务处理
assert intent != null;
String taskName = intent.getStringExtra(“taskName”);
switch (taskName) {
} } } ```case "task1":
Log.e(TAG, "onHandleIntent: task1" );
break;
case "task2":
Log.e(TAG, "onHandleIntent: test2" );
break;
开启服务 ```kotlin public void intentstartListener(View view) {
// 请求1
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra("taskName","task1");
startService(intent);
Intent intent2 = new Intent(this, MyIntentService.class);
intent2.putExtra("taskName","task2");
startService(intent2);
startService(intent);
// //多次启动
}
4. 测试结果<br />2019-04-17 18:49:05.274 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onCreate:<br />2019-04-17 18:49:05.275 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onStartCommand:<br />2019-04-17 18:49:05.276 22163-22816/com.kiwilss.lxkj.fourassembly E/MMM: onHandleIntent: task1<br />2019-04-17 18:49:05.280 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onStartCommand:<br />2019-04-17 18:49:05.280 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onStartCommand:<br />2019-04-17 18:49:05.280 22163-22816/com.kiwilss.lxkj.fourassembly E/MMM: onHandleIntent: test2<br />2019-04-17 18:49:05.282 22163-22816/com.kiwilss.lxkj.fourassembly E/MMM: onHandleIntent: task1<br />2019-04-17 18:49:05.284 22163-22163/com.kiwilss.lxkj.fourassembly E/MMM: onDestroy:
<a name="5a431a85"></a>
#### 7.远程服务
- 远程服务与本地服务的区别
- 远程服务与本地服务最大的区别是:远程Service与调用者不在同一个进程里(即远程Service是运行在另外一个进程);而本地服务则是与调用者运行在同一个进程里
- 二者区别的详细区别如下图: ```
- 使用场景
多个应用程序共享同一个后台服务(远程服务).即一个远程Service与多个应用程序的组件(四大组件)进行跨进程通信 使用demo
- 新建AIDL, 并在在新建AIDL文件里定义Service需要与Activity进行通信的内容(方法),并进行编译(Make Project)
新建服务,在服务中实现 AIDL 定义的接口方法, 服务如下
public class LongService extends Service {
//@androidx.annotation.Nullable
// 实例化AIDL的Stub类(Binder的子类)
AIDL_Service1.Stub mBinder = new AIDL_Service1.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
Log.e(TAG, "basicTypes: " );
}
@Override
public void AIDL_Service() throws RemoteException {
Log.e(TAG, "AIDL_Service: 客户端通过AIDL与远程后台成功通信" );
}
};
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: " );
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: " );
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: " );
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: " );
}
}
清单文件注册服务 ```java
1. 在 Activity 中调用
```java
/**远程服务
* @param view
*/
//远程服务的serviceconnect
AIDL_Service1 mAIDL_Service;
private ServiceConnection mLongSc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//使用AIDLService1.Stub.asInterface()方法获取服务器端返回的IBinder对象
//将IBinder对象传换成了mAIDL_Service接口对象
mAIDL_Service = AIDL_Service1.Stub.asInterface(iBinder);
try {
//通过该对象调用在MyAIDLService.aidl文件中定义的接口方法,从而实现跨进程通信
mAIDL_Service.AIDL_Service();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
public void longListener(View view) {
//通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定
//参数与服务器端的action要一致,即"服务器包名.aidl接口文件名"
// Intent intent = new Intent("scut.carson_ho.service_server.AIDL_Service1");
//
// //Android5.0后无法只通过隐式Intent绑定远程Service
// //需要通过setPackage()方法指定包名
// intent.setPackage("scut.carson_ho.service_server");
Intent intent = new Intent(this, LongService.class);
//绑定服务,传入intent和ServiceConnection对象
bindService(intent, mLongSc, Context.BIND_AUTO_CREATE);
}
- 测试结果
2019-04-18 11:27:25.712 25501-25501/com.kiwilss.lxkj.fourassembly:remote E/MMM: onCreate:
2019-04-18 11:27:25.713 25501-25501/com.kiwilss.lxkj.fourassembly:remote E/MMM: onBind:
2019-04-18 11:27:25.716 25501-25513/com.kiwilss.lxkj.fourassembly:remote E/MMM: AIDL_Service: 客户端通过AIDL与远程后台成功通信三.参考文档
Android四大组件:Service史上最全面解析
Android四大组件
Android 绑定远程服务(aidl文件的使用)
demo 地址