1. service是什么?及其生命周期?
在前台不可见,但是承担大部分数据处理工作(劳模),它和Activity的地位是并列的,区别在于:Activity运行与前台,Service运行于后台,没有图形用户界面,通常他为其他的组件提供后台服务或监控其他组件的运行状态。
service的生命周期:
- onCreate():当service第一次被启动的时候就会调用此方法
- onStartConnand():当service第一次启动onCreate方法执行完毕之后就会调用此方法,再次进入service的时候就会直接进入该方法,在此方法内可以进行大量的业务逻辑处理
- onDestroy():当停止一个service的时候就会调用此方法
2. Service开启的方式?
- 2.1 startService开启后Activity和Service就没有关系了,即使调用者activity退出了,服务还会长期的在后台运行【不可以调用服务里的方法】
startService: onCreate ->onStartCommand
stopService:onDestroy
image.gif
- 2.2 bindService,开启后Activity和Service的生命周期就捆绑在了一起,如果调用者activity 销毁了,服务也跟着销毁【间接调用服务里的方法】
bindService:onCreate->onBind
unbindService:onUnbind->onDetroy
image.gif
- 2.3. 混合调用
需求:既要保证服务长期在后台运行,又想去调用服务里面的方法
技巧:1.先开启服务 2.绑定服务
-
开启服务:
startService --> bindService
onCreate -->onStartCommand -->onBind -
停止服务:
unBindService -- > stopService
onUnbind--> onDestory -
开启服务:
bindService --> startService
onCreate -->onBind --> onStartCommand -
停止服务:
unBindService -- > stopService
onUnbind --> onDestory步骤:
-
2.3.1 开启服务(保证服务的后台长期运行) startService->onCreate() ->onStartCommand;
-
2.3.2 绑定服务(获取中间人,间接的调用服务里面的方法) bindService->onBind();
-
2.3.3 关闭程序,调用者退出,服务被解绑unBinderService()解除绑定服务,失去服务的连接,会调用onUnbind方法
-
2.3.4 服务会长期在后台运行 stopService()停止服务
如果服务被绑定过了,直接利用stopService是停不掉的,必须要显示的解除绑定服务,服务才能被停掉,服务只能被解除绑定一次,多次解除绑定服务 应用程序会抛出异常
-
image
image.gif
image image.gif
3. Service使用场景举例?
音乐播放器
- 3.1 播放逻辑写在Service里面(保证Service长期后台运行)startService
- 3.2 快进、快退、暂停调用服务里面的方法bindService
- 3.3 activity关闭的时候 不需要调用服务的方法了unbindService
- 3.4 关闭播放器的时候 stopService
4. 开机自启Service?
- 4.1 实现一个开机监听广播
public class BootBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context,XXXclass);
context.startService(service);
//启动应用,参数为需要自动启动的应用的包名
Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
context.startActivity(intent );
}
}
image.gif
- 4.2 配置广播接收器的过滤器intent-filter
<receiver android:name="BootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
image.gif
4.3 添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
image.gif
5. 什么是进程,什么是线程,进程分类?
进程就是正在进行中的程序,它是系统分配资源的基本单位,线程就是一次单一顺序的执行控制流, 一个进程里面可以有多个线程,一般情况下,一个应用程序会对应一个进程,关闭应用就是关闭了所有的界面,关闭所有的activity,应用程序的进程是不会关闭掉的,仍然在后台长期的运行,当系统内存不够用的时候会优先关闭空进程和后台进程。
采用一组组策略,帮助我们自动的管理进程,进程按照优先级分为不同的等级:
- 5.1 前台进程 用户可以看到这个进程里的某一个activity界面,可以操作这个界面
- 5.2 可见进程 用户仍然可以看到这个进程的某个activity,但是不可以操作这个界面
- 5.3 服务进程 如果一个应用程序有一个服务在后台运行
- 5.4 后台进程 没有任何的服务进程,打开一个activity后,按了home键,最小化了
- 5.5 空进程 没有任何活动组件存在的进程
6.简述通过Binder调用服务流程?
-
6.1 客户端调用服务代理方法开始【方法调用】
-
6.2 服务代理方法准备方法参数数据包和方法执行结果数据包【准备数据】
-
6.3 客户端调用binder驱动层的binder对象的transact方法进行数据传递【数据传递】
-
6.4 服务端binder对象的onTransact方法开启响应并进行事件分发处理【事件分发】
-
6.5 服务端读取方法参数数据包并调用真正的服务方法【数据处理】
-
6.6 服务端服务方法执行完毕将执行结果写入结果数据包并且返回【返回结果】
-
6.7 Binde驱动层的binder接受返回执行结果并且继续向客户端返回【继续返回】
-
6.8 客户端接收处理结果数据【接收数据】
image image.gif
7.创建绑定服务都有那几种方式?
- 7.1 扩展 Binder 类:客户端和服务端在同一个应用,同一个进程
- 7.2 使用 Messenger:这是跨进程通信的最简单方法,方法调用需要排队
- 7.3 使用 AIDL:如果同时要执行服务端的多个方法,则采用aidl的方法
8.通过扩展binder实现本地服务调用?
9.利用Messanger进行跨进程通信流程?
Messenger封装了Binder和Handler,有了Handler,Messenger就可以发送消息了,有了Binder,Messanger就可以远程通信了
- 9.1 服务端利用Handler创建一个服务端的Messenger【创建服务端信使】
- 9.2 客户端利用服务端返回的Binder构造一个服务端的Messenger【接受服务端信使】
- 9.3 客户端利用Handler创建一个客户端的Messenger【创建客户端信使】
- 9.4 客户端利用拿到服务端信使给服务端发送消息携带上客户端信使【把客户端信使发送给服务端】
- 9.5 服务端接受消息就拿到客户端信使【接受客务端信使】
结果:客户端拿到了服务端的信使【使用binder构造】,服务端拿到了客户端信使【使用消息携带】,然后就可以互发信息了
服务端:
public class MyService extends Service {
private Messenger mServidceMessenger;// 服务端消息信使
private Messenger mClientMessenger;// 客户端消息信使
private Handler mServideHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
mClientMessenger = msg.replyTo;
break;
}
super.handleMessage(msg);
}
};
@Override
public void onCreate() {
mServidceMessenger = new Messenger(mServideHandler);
}
@Override
public IBinder onBind(Intent intent) {
return mServidceMessenger.getBinder();
}
}
image.gif
客户端:
pubblic class MainActivity extends Activity{
private Messenger mServidceMessenger;// 服务端消息信使
private Messenger mClientMessenger;// 客户端消息信使
@Override
public void onCreate(Bundle bundle){
bindService(mService, new MyServiceConnection(), Context.BIND_AUTO_CREATE);
}
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mServiceMessenger = new Messenger(iBinder);
mClientMessenger = new Messenger(mClientHandler);
Message msg = Message.obtain();
msg.replyTo = mClientMessenger;
msg.what = 0;
mServiceMessenger.send(msg);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
private Handler mClientHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
}
image.gif
10. AIDL架构分析?
image image.gif
image image.gif
11. AIDL跨进程服务调用工作原理?AIDL实现的步骤?
客户端和服务端通信协议解决了两个问题,服务端和客户端约定了方法参数列表顺序;约定了方法的ID标识
服务端:
- 继承Service创建服务子类
- 定义服务所对外提供的服务接口(跨进程服务则需要创建aidl接口,创aidl实体)
- 继承Binder建立中间人对象并且实现服务接口
- 通过onBinder回调方法返回中间人对象
- 在清单文件里面发布服务
客户端:
-
创建一个隐式意图Intent
-
继承ServiceConnection创建一个服务连接对象conn
-
通过bindService绑定服务
-
在bindService的回调方法onServiceConnectioned里获取服务端的中间人对象
-
通过中间人对象调用服务里面的方法
具体流程:
-
11.1 创建接口服务
IMyService.aidl
package com.ryg.sayhi.aidl;
import com.ryg.sayhi.aidl.Student;
interface IMyService {
List < Student > getStudent();
void addStudent(in Student student);
}
image.gif
- 11.2 创建一个AIDL实体
Student.aidl
package com.ryg.sayhi.aidl;
parcelable Student;
image.gif
- 11.3 创建一个Parcelable实体
Student.java
package com.ryg.sayhi.aidl;
public final class Student implements Parcelable {
public int sno;
public String name;
public Student() {}
}
image.gif
- 11.4 创建服务端service
public class MyService extends Service{
private final IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public List < Student > getStudent()throws RemoteException {}
@Override
public void addStudent(Student student)throws RemoteException {}
//在这里可以做权限认证,return false意味着客户端的调用就会失败,比如下面,只允许包名为com.example.test的客户端通过,
//其他apk将无法完成调用过程
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
String packageName = null;
String[]packages = MyService.this.getPackageManager().
getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName = packages[0];
}
Log.d(TAG, "onTransact: " + packageName);
if (!PACKAGE_SAYHI.equals("com.example.test")) {
return false;
}
return super.onTransact(code, data, reply, flags);
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
image.gif
- 11.5 在AndroidMenifest中声明service
<service
android : name = "com.ryg.sayhi.MyService"
android : process = ":remote"
android : exported = "true" >
< intent - filter >
< category android : name = "android.intent.category.DEFAULT" / >
< action android : name = "com.ryg.sayhi.MyService" / >
< / intent - filter >
< / service >
image.gif
- 11.6 创建客户端
import com.ryg.sayhi.aidl.IMyService;
import com.ryg.sayhi.aidl.Student;
public class MainActivity extends Activity implements OnClickListener {
private IMyService mIMyService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mIMyService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMyService = IMyService.Stub.asInterface(service);
}
};
@ Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
}
}import com.ryg.sayhi.aidl.IMyService;
import com.ryg.sayhi.aidl.Student;
public class MainActivity extends Activity implements OnClickListener {
private IMyService mIMyService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mIMyService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMyService = IMyService.Stub.asInterface(service);
}
};
@ Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(intentService, mServiceConnection, BIND_AUTO_CREATE);
}
}
image.gif
12. AIDL 使用注意事项?
- 12.1 建立aidl实体时必须在aidl文件夹,对应的java文件在对应的java文件夹
- 12.2 建立aidl实体时,需要声明该文件所在的包
- 12.3 建立实体是使用parcelable关键字
- 12.4 建立的实体必须实现Parcelable接口
- 12.5 aidl实体和其对应的java实体所在的包名必须保持一直
- 12.6 建立aidl接口时,如果用到了复合类型的数据需要在aidl接口中导入,导入的是aidl文件,而不是java文件
- 12.7 建立的aidl接口时,interface前不能有任何修饰符,方法名前不能有任何的修饰符
- 12.8 建立aidl接口的方法时如果有参数则执行参数的类型为in
- 12.9 aidl接口,基本类型、String、List、Map、CharSequence类型之外,其他类型都要导入包,即使他们在同一包里面也需要导包
- 12.10 如果调用本地服务则是显示意图,如果调用远程服务则用隐式意图
- 12.11 获取远程服务的中间人对象是用stub.asInterface方法
13.如何保证Service长期存活
- 13.1 通过推送服务保持存活
- 13.2 将Service运行于另外一个进程当中 (android:process=":remote" )
- 13.3 在onStartCommand方法返回start_sticky,同时在onDestroy方法中进行重启服务【kill掉的话会自动重启】
- 13.4 把Service所在的App提升至系统应用级别(android:persistent=”true”)
- 13.5 为Service建立一个守护服务
- 13.6 通过监听系统广播来唤醒服务
总结:
1,6简单粗暴可以保证完全存活
4,5常用的方案
2,3比较轻量级
将Service设置为前台服务:(startForeground(int, Notification))
编码通过双服务实现服务长存?
https://www.cnblogs.com/zhujiabin/p/6073529.html
- 1.在AndroidMnifest.xml进行配置?
<service android:name="ServiceOne" android:process=":remote">
<intent-filter>
<action android:name="com.example.servicedemo.ServiceOne"/>
</intent-filter>
</service>
<service android:name="ServiceTwo" android:process=":remote">
<intent-filter>
<action android:name="com.example.servicedemo.ServiceTwo"/>
</intent-filter>
</service>
image.gif
- 2.activit中启动服务
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceOne = new Intent();
serviceOne.setClass(MainActivity.this, ServiceOne.class);
startService(serviceOne);
Intent serviceTwo = new Intent();
serviceTwo.setClass(MainActivity.this, ServiceTwo.class);
startService(serviceTwo);
}
public static boolean isServiceWorked(Context context, String serviceName) {
ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) myManager.getRunningServices(Integer.MAX_VALUE);
for (int i = 0; i < runningService.size(); i++) {
if (runningService.get(i).service.getClassName().toString().equals(serviceName)) {
return true;
}
}
return false;
}
}
image.gif
- 3.创建服务1
public class ServiceOne extends Service {
public final static String TAG = "com.example.servicedemo.ServiceOne";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_STICKY;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "ServiceOne Run: "+System.currentTimeMillis());
boolean b = MainActivity.isServiceWorked(ServiceOne.this, "com.example.servicedemo.ServiceTwo");
if(!b) {
Intent service = new Intent(ServiceOne.this, ServiceTwo.class);
startService(service);
Log.e(TAG, "Start ServiceTwo");
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
image.gif
- 4.创建服务2
public class ServiceTwo extends Service {
public final static String TAG = "com.example.servicedemo.ServiceTwo";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_REDELIVER_INTENT;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "ServiceTwo Run: " + System.currentTimeMillis());
boolean b = MainActivity.isServiceWorked(ServiceTwo.this, "com.example.servicedemo.ServiceOne");
if(!b) {
Intent service = new Intent(ServiceTwo.this, ServiceOne.class);
startService(service);
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
image.gif
网友评论