美文网首页
Android四大组件之Service详解

Android四大组件之Service详解

作者: 门心叼龙 | 来源:发表于2019-04-16 19:22 被阅读0次

    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


    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

    相关文章

      网友评论

          本文标题:Android四大组件之Service详解

          本文链接:https://www.haomeiwen.com/subject/queiwqtx.html