Android四大组件之Service详解

版权声明:本文出自门心叼龙的博客,转载请注明出处。 https://blog.csdn.net/geduo_83/article/details/86551894

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
  • 2.2 bindService,开启后Activity和Service的生命周期就捆绑在了一起,如果调用者activity 销毁了,服务也跟着销毁【间接调用服务里的方法】 
bindService:onCreate->onBind
unbindService:onUnbind->onDetroy
  • 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是停不掉的,必须要显示的解除绑定服务,服务才能被停掉,服务只能被解除绑定一次,多次解除绑定服务 应用程序会抛出异常


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 );
    }
}
  • 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>

4.3 添加权限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 

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 客户端接收处理结果数据【接收数据】

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();
    }
}

客户端:

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);
        }
    };
} 

10. AIDL架构分析?

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);
}
  • 11.2 创建一个AIDL实体
Student.aidl
package com.ryg.sayhi.aidl;
parcelable Student;
  • 11.3 创建一个Parcelable实体

Student.java

package com.ryg.sayhi.aidl;
public final class Student implements Parcelable {
    public int sno;
    public String name;
    public Student() {}
}
  • 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;
    }
}
  • 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 >
  • 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);
}
}

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>
  • 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;
    }
}
  • 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;
    }

}
  • 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;
    }

}

猜你喜欢

转载自blog.csdn.net/geduo_83/article/details/86551894