Service
生命周期
1、通过startService()方式,onCreate()–>onStartCommand()–>onDestroy()
注:
- 若一个Service被startService()多次启动,那么onCreate()也只会调用一次,即Service实例只有1个
- 整个生命周期的方法中,只有onStartCommand()可多次调用,其他只能调用一次
- onStartCommand调用次数=startService调用次数
特点:调用者退出后Service仍然存在
应用场景:服务不需与Activity和Service通信
示例代码:
tv_content.setOnClickListener {
val intent = Intent(this@BActivity,StartServiceDemo::class.java)
intent.putExtra("content","nihao")
startService(Intent(intent))
}
tv_content_stop.setOnClickListener {
val intent = Intent(this@BActivity,StartServiceDemo::class.java)
stopService(Intent(intent))
}
定时循环任务示例代码:
public class VersionCheckServices extends Service {
private static String TAG = VersionCheckServices.class.getName();
/**
* 定时器对象
*/
private AlarmManager manager;
private PendingIntent pendingIntent;
private final int LOOP_TIME = 60;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
}
@Override
public void onDestroy() {
if (pendingIntent != null) {
manager.cancel(pendingIntent);
}
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if ((ModifySetUtils.isCodeCheckVersion() || ModifySetUtils.isCheckVersion() || ModifySetUtils.isFourCheckVersion()) && !SPUtils.isCheckUser()) {
if (!AppUtils.isAppForeground()) {
new CheckVersionPassPresenter().dealCheckVersion(this,checkVersionCallBack);
} else {
next(LOOP_TIME);
}
} else {
//非审核版本就不需要继续调用服务了
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
/**
* 检查审核版本的回调
*/
private HttpOnNextListener checkVersionCallBack = new HttpOnNextListener() {
@Override
public void onError(ApiException e) {
next(LOOP_TIME);
}
@Override
public void onNext(CheckPassVersionResult checkPassVersionResult) {
if(checkPassVersionResult.getData() != null && checkPassVersionResult.getData().isPass()){
SPNoCleanUtil.saveCheckVersion(true);
IntentUtils.startGuideActivity(VersionCheckServices.this);
} else {
next(LOOP_TIME);
SPNoCleanUtil.saveCheckVersion(false);
}
}
@Override
public void onDealCodeNext(CheckPassVersionResult baseResult) {
next(LOOP_TIME);
SPNoCleanUtil.saveCheckVersion(false);
}
};
/**
* 设置定时器,准备下次调用
*
* @param time 调用时间,秒
*/
private void next(int time) {
Intent intent = new Intent(this, VersionCheckServices.class);
pendingIntent = PendingIntent.getService(this, 0, intent, 0);
manager.set(AlarmManager.RTC, System.currentTimeMillis() + time * 1000, pendingIntent);
}}
2、通过bindService()方式,onCreate()–>onBind()–>onUnbind()–>onDestroy()
注:
- 客户端通过一个IBinder接口与服务进行通信
- 若一个Service被BindService()多次启动,那么onCreate()也只会调用一次,即Service实例只有1个
- 多个客户端可绑定到同一个服务上,当所有客户端都解绑后,系统会销毁服务
特点:调用者退出后,随着调用者销毁
应用场景:服务需与Activity和Service通信、需控制服务开始时刻
bindService()方式的示例代码:
先定义Service子类:
public class BindServiceDemo extends Service {
private String TAG = BindServiceDemo.class.getSimpleName();
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG,"onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG,"onDestroy");
}
public class MyBinder extends Binder{
public void service_connect_Activity() {
Log.i(TAG,"Service关联了Activity,并在Activity执行了Service的方法");
}
}}
在AndroidManifest.xml中注册
使用:
private var myBinder:BindServiceDemo.MyBinder?= null
//创建ServiceConnection的匿名类
private val connection = object : ServiceConnection {
//重写onServiceConnected()方法和onServiceDisconnected()方法
//在Activity与Service解除关联的时候调用
override fun onServiceDisconnected(name: ComponentName) {}
//在Activity与Service关联的时候调用
override fun onServiceConnected(name: ComponentName, service: IBinder) {
//实例化Service的内部类myBinder
//通过向下转型得到了MyBinder的实例
myBinder = service as BindServiceDemo.MyBinder
//在Activity调用Service类的方法
myBinder?.service_connect_Activity()
}
}
tv_bind_service.setOnClickListener {
val intent = Intent(this@BActivity,BindServiceDemo::class.java)
bindService(intent,connection, Context.BIND_AUTO_CREATE)
}
tv_unbind_service.setOnClickListener {
//仅此示例,正常要判是否已经绑定成功
unbindService(connection)
}
IntentService
多线程IntentService
本质:Handler + HandlerThread
为什么要使用IntentService呢,
因为1、普通的Service不是一个单独的进程,它和它的应用程序在同一个进程中
2、Service不是一个线程,就意味着应该避免在Service中进行耗时操作
工作流程:客户端通过startService(Intent)来启动IntentService; 我们并不需要手动地区控制IntentService,当任务执行完后,IntentService会自动停止; 可以启动IntentService多次,每个耗时操作会以工作队列的方式在IntentService的 onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一,再到二这样!
生命周期: onCreate() –> onStartCommand() –> onHandleIntent() –> onDestroy()
多次调用 startService(Intent)会多次调用onStartCommand()和onHandleIntent()
注意:
一. 工作任务队列 = 顺序执行
由于onCreate()只会调用一次 = 只会创建1个工作线程
二、不建议通过 bindService() 启动 IntentService
因为bindService()的生命周期是onCreate() –> onBind() –> onunBind() –> onDestory(),并不会调onStartCommand(),因此不会将消息发送到消息队列,那么onHandleIntent()将不会回调,即无法实现多线程操作
远程服务Service
远程服务与本地服务最大的区别:远程Service与调用者不在同一个进程里,而本地服务则是与调用者在同一个进程里
使用场景:
多个应用程序共享同一个后台服务(远程服务)
具体使用:
为了让远程Service与多个应用程序的组件(四大组件)进行跨进程通信(IPC),需要使用AIDL。
AIDL:Android接口定义语言
操作步骤:
一:先定义后台服务(服务器端)
步骤1:新建AIDL文件,创建提供给客户端的接口,定义好接口方法
步骤2:在Service子类中实现AIDL中定义的接口方法,即回调给客户端接口和客户端通信
关键通过AIDL_Service1.Stub mBinder = new AIDL_Service1.Stub()。生成binder,然后binder在客户端绑定成功后onServiceConnected传入改binder,然后在客户端通过AIDL_Service1.Stub.asInterface(binder)反转成AIDL_Service1实例,就可以拿到服务器端传过来的信息
示例代码:
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidl_service1 = AIDL_Service1.Stub.asInterface(service);
try {
aidl_service1.toDoService();
} catch (RemoteException e) {
e.printStackTrace();
}
}
步骤3:在AndroidManifest.xml中注册为android:exported=”true”的,还有加上
二:客户端
步骤1:拷贝服务器端的aidl文件到main目录下,是整个aidl目录拷贝过来,不要做任何改动
步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
步骤3:通过bindService()方法启动,intent指定服务器端的服务名称和包名,绑定远程Service
示例代码:
服务器
定义aidl接口(鼠标右键new里面有AIDL,创建完Rebuild Project):
定义Service子类:
public class AIDLServiceDemo extends Service {
private String TAG = AIDLServiceDemo.class.getSimpleName();
AIDL_Service1.Stub mBinder = new AIDL_Service1.Stub() {
@Override
public void toDoService() throws RemoteException {
Log.i(TAG,"客户端通过AIDL与远程后台成功通信");
}
};
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG,"onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG,"onDestroy");
}}
在AndroidManifest.xml中注册:
客户端:
完全拷贝aidl文件过来:
绑定和使用:
public class MainActivity extends AppCompatActivity {
private TextView tvBindService;
private AIDL_Service1 aidl_service1;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidl_service1 = AIDL_Service1.Stub.asInterface(service);
try {
aidl_service1.toDoService();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvBindService = findViewById(R.id.tv_bind_remote_service);
tvBindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.cong.myapplication.service.AIDL_Service1");
intent.setPackage("com.cong.myapplication.service");
bindService(intent,connection,BIND_AUTO_CREATE);
}
});
}}
Androidmanifest里Service的常见属性说明
android:name:Service的类名
android:permission:申明此Service的权限。注:有提供了该权限的应用才能控制或连接此服务
android:process:表示该服务是否在另一个进程中运行(远程服务)。注:不设置默认为本地服务;remote则设置成远程服务
android:exported:该服务是否能够被其他应用程序所控制或连接
注:不设置默认为false
参考:https://www.jianshu.com/p/d963c55c3ab9