SerVice
- Service就是默默运行在后台的组件,可以理解为是没有前台的activity,适合用来运行不需要前台界面的代码
- 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启
开启方式
- startService
- 该方法启动的服务所在的进程属于服务进程
- Activity一旦启动服务,服务就跟Activity一毛钱关系也没有了
- bindService
- 该方法启动的服务所在进程不属于服务进程
- Activity与服务建立连接,Activity一旦死亡,服务也会死亡
服务的分类
- 本地服务:指的是服务和启动服务的activity在同一个进程中
- 远程服务:指的是服务和启动服务的activity不在同一个进程中
服务的生命周期
onCreate–>onStartCommand–>onDestory,与activity的不同,没有
onRestart和onResume,这一点注意。
启动方式示例
建立一个服务时,和广播一样,这里要继承自Service类
有两种方式启动和关闭
//这里是第一种方式
startService(intent);
stopService(intent);
第二种方式中,绑定服务需要传递三个参数,第一个就是要调用服务的意图对象,
第二个是一个ServiceConnection对象,这里需要实现该类,里面有有两个重写
的方法;最后一个表示标志位,一般用BIND_AUTO_CREATE
bindService(intent, conn, BIND_AUTO_CREATE);//绑定服务
//解绑服务
unbindService(conn);
class MyServiceConn implements ServiceConnection{
//服务连接成功时,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
}
//服务失去连接时,此方法调用
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stu
}
}
简单示例
需求:如果服务类中有一个方法,怎么去调用
绑定服务时,会触发服务的onBind方法,此方法会返回一个Ibinder的对象给
MainActivity,通过这个对象访问服务中的方法
服务类中的方法
@Override
public IBinder onBind(Intent intent) {
// 返回一个Binder对象,这个对象就是中间人对象
return new Tim();
}
class Tim extends Binder implements PublicBusiness{
public void run(){
banZheng();
}
}
public void banZheng(){
System.out.println("帮你来办证");
}
PublicBusiness接口中只定义一个未实现的run方法就行
public interface PublicBusiness {
void run();
}
主activity中的调用步骤
private Intent intent;
private MyServiceConn conn;
PublicBusiness pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, LeaderService.class);
conn = new MyServiceConn();
//绑定服务
bindService(intent, conn, BIND_AUTO_CREATE);
}
public void click(View v){
//调用服务的办证方法
pb.run();
}
class MyServiceConn implements ServiceConnection{
//连接服务成功,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
pb = (PublicBusiness) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
该示例有点类似于找领导办事一样,需要通过一个中间人与领导进行交流,而小
员工与中间人交流,而中间人就是定义的Tim类。
使用服务注册广播接收者
这里的广播用的不是在清单文件中操作的方式,而是使用代码注册
public class ScreenReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if(Intent.ACTION_SCREEN_OFF.equals(action)){
System.out.println("屏幕关闭");
}
else if(Intent.ACTION_SCREEN_ON.equals(action)){
System.out.println("屏幕打开");
}
}
}
当点击按钮时,开启服务,并且触发服务中的广播接收者代码
//主activity中
public void start(View v){
startService(intent);
}
public void stop(View v){
stopService(intent);
}
//服务中
@Override
public void onCreate() {
super.onCreate();
//1.创建广播接收者对象
receiver = new ScreenReceiver();
//2.创建intent-filter对象
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
//3.注册广播接收者
registerReceiver(receiver, filter);
}
@Override
public void onDestroy() {
super.onDestroy();
//解除注册,解除注册之后,广播接收者将失去作用
unregisterReceiver(receiver);
}
服务分为本地和远程之说,那么如何启动远程的服务内容呢
这里需要用到一个知识点:AIDL(安卓接口定义语言),是进程间通信接口,
作用就是用于进程间通信。应用场景:远程服务中的中间人对象,其他应
用是拿不到的,那么在通过绑定服务获取中间人对象时,就无法强制转换,
使用aidl,就可以在其他应用中拿到中间人类所实现的接口
示例步骤
1 创建两个项目,一个上面部署服务,另外一个在主activity上添加一个按钮,
当点击的时候,触发项目1上的服务。
2 过程和简单示例中的很相似,只不过相当于把主activity和服务分到两个项目
中实现,还有一点不同的是:这里的PayInterface.java接口类,后缀要改
为:PayInterface.aidl文件,并且服务中实现的部分也要改变:
public class PayService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new Mypay();
}
//这里是继承了Stub类
class Mypay extends Stub{
public void pay(){
PayService.this.pay_money();
}
}
public void pay_money(){
System.out.println("调用pay方法");
System.out.println("加密用户名,密码");
System.out.println("建立连接");
}
}
主方法中调用
private Intent intent;
private MyServiceConn conn;
private PayInterface pin;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent=new Intent();
conn=new MyServiceConn();
intent.setAction("com.itma.pay");
bindService(intent, conn, BIND_AUTO_CREATE);
}
class MyServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
pin=Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
public void click(View v){
try {
pin.pay();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
进程间通信的步骤
1. 把远程服务的方法抽取成一个单独的接口java文件
2. 把接口java文件的后缀名改成aidl
3. 在自动生成的PayInterface .java文件中,有一个静态抽象类Stub,它已经继承了binder类,实现了PayInterface接口,这个类就是新的中间人
4. 把aidl文件复制粘贴到另外一个项目,粘贴的时候注意,aidl文件所在的包名必须跟05项目中aidl所在的包名一致
5. 在另外一个项目中,强转中间人对象时,直接使用Stub.asInterface()
进程优先级
前台进程:拥有前台activity(onResume方法被调用),以下都能成为前台进程
- 拥有一个正在与用户交互的activity(onResume调用)的进程
- 拥有一个与正在和用户交互的activity绑定的服务的进程
- 拥有一个正在“运行于前台”的服务——服务的startForeground方法调用
- 拥有一个正在执行以下三个生命周期方法中任意一个的服务(onCreate(), onStart(), or onDestroy())
- 拥有一个正在执行onReceive方法的广播接收者的进程
可见进程:拥有可见activity(onPause方法被调用)
- 拥有一个不在前台,但是对用户依然可见的activity(onPause方法调用)的进程
- 拥有一个与可见(或前台)activity绑定的服务的进程
- 服务进程:不到万不得已不会被回收,而且即便被回收,内存充足时也会被重启
- 后台进程:拥有后台activity(activity的onStop方法被调用了),很容易被回收
- 空进程:没有运行任何activity,很容易被回收