Android四大组件之服务Service的用法

一、 进程概念介绍

四大组件都是运行在主线程
Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过来声明。可以通过contect.startservice和contect.bindserverice来启动。
Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。

二、服务的使用

 定义一个新的服务,要用一个类去继承Service这个类,Service类中有一个抽象方法onBind()。

一般处理定义一个服务去处理一些事情需要重新覆写三个方法
①onCreate()
②onStartCommand(Intent intent , int flags ,int startId)
③onDestroy()

   onCreate()方法会在服务创建的时候调用
   onStartCommand()方法会在每次服务启动的时候调用
   onDestroy()方法会在服务销毁的时候调用

onCreate()和 onStartCommand()方法的区别:
答:oncreate()方法是在服务第一次创建的时候调用,而 onStartCommand()方法则在每次启动服务的时候都会调用。

注意:每一个服务都需要在AndroidManifest.xml文件中注册
[图片]

三、启动服务和停止服务

定义一个自定义服务类,然后在主函数中通过按钮点击事件进行服务的启动和停止
  通过startService()方法启动服务

通过stopService()方法停止服务
代码如下:
[图片]

注意:startService()和stopService()方法都是定义在Context类中的,所以在活动中可以直接调用这两个方法,完全是由活动来决定服务何时停止的。如果想让服务自己停止,则只需要在服务类MyService中的任何一个位置调用stopSelf()方法就可以让这个服务停下来

Android中的服务 也是在后台运行 可以理解成是在后台运行并且是没有界面的Activity

五种服务的级别:

(1)Foreground process 前台进程 用户正在交互 可以理解成相 当于 Activity执行onResume方法
(2)Visible process 可视进程 用户没有在交互 但用户还一直能看得见页面 相当于Activity执行了onPause方法
(3)Service Process 服务进程 通过startService()开启了一个服务
(4)Background process 后台进程 当前用户看不见页面 相当于Activity执行了onStop方法
(5)Empty process 空进程


service的两种模式(startService()/bindService()不是完全分离的

● 本地服务 Local Service 用于应用程序内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。
用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
● 远程服务 Remote Service 用于android系统内部的应用程序之间。
它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。

可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

生命周期

服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。
1. 使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。
如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务
只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。

2. 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定
多次调用Context.bindService()方法并不会导致该方法被多次调用。
采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。

看看官方给出的比较流程示意图:
这里写图片描述

官方文档告诉我们,一个service可以同时start并且bind,在这样的情况,系统会一直保持service的运行状态如果service已经start了或者BIND_AUTO_CREATE标志被设置。如果没有一个条件满足,那么系统将会调用onDestory方法来终止service.所有的清理工作(终止线程,反注册接收器)都在onDestory中完成。

拥有service的进程具有较高的优先级
官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。

1. 如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。

2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.

3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。

4. 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。

如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。


二、start方式开启服务和bindService方式开启服务的特点

服务是在后台运行 可以理解成是没有界面的activity
定义四大组件的方式都是一样的
定义一个类继承Service
1.特点:
(1)服务通过startservice方式开启 第一次点击按钮开启服务 会执行服务的onCreate 和 onStart方法
(2)如果第二次开始再点击按钮开启服务 服务只会执行onStrat方法
(3)服务被开启后 会在设置页面里面的 running里面找得到这个服务
*(4)startservice 方式开启服务 服务就会在后台长期运行 直到用户手工停止 或者调用StopService方法 服务才会被销毁

bindService()理解:

自定义的Service服务类里面的onBind()方法是在activity中执行了bindService()绑定服务的操作后执行的。
bindService()方法中药传入三个参数:
第一个参数是Intent对象;

第二个参数是建立连接的对象,即ServiceConnection的对象,当执行了bindService()后,服务和activity之间的联系便建立起来了,此时会回调Service中的onBind()方法,该方法返回一个IBinder对象,这个对象我们可以在该类中自定义一个MyBinder类继承Bind抽象类,在里面实现服务的方法,当onBind()执行后,活动中的ServiceConnection类的onServiceConnection()方法会执行,在该方法里有传过来的一个参数IBinder service,将这个参数拿出来,通过这个对象去调用服务中的方法,相当于中间人;

//服务中自定义的中间人对象类
public  class MyBinder extends Binder{
    public void startDownload(){
xxxxxxxxxx;
    };
}

......

//连接服务的对象
 private ServiceConnection connection = new ServiceConnection() {  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service) {  
        myBinder = (MyService.MyBinder) service;  
            myBinder.startDownload();  
        }  
    };  

第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。

[图片]

2.bindService 方式开启服务的特点

(1)当点击按钮第一次开启服务 会执行服务的onCreate方法 和 onBind()方法
(2) 当第二次点击按钮在调用bindservice 服务没有响应
**(3) 当activity销毁的时候服务也销毁 不求同时生但求同时死
(4)通过bind方式开启服务 服务不能再设置页面里面找到 相当于是一个隐形的服务

(5)bindservice不能多次解绑 多次解绑会报错

3 使用服务注册特殊的广播接收者

(1)创建我们要注册的广播接收者

  public class ScreenReceiver extends BroadcastReceiver {
    @Override
        public void onReceive(Context context, Intent intent) {
            //获取广播事件的类型
        String action = intent.getAction();

            if ("android.intent.action.SCREEN_OFF".equals(action)) {

            System.out.println("说明屏幕锁屏了");
        }else if("android.intent.action.SCREEN_ON".equals(action)){

                System.out.println("说明屏幕解锁了");
            }
    }
    }

(2)创建一个服务 用来注册广播接收者 代码如下

 public class ScreenService extends Service {

    private ScreenReceiver receiver;
    @Override
        public IBinder onBind(Intent intent) {
            return null;
    }

        //当服务第一次启动的时候调用
        @Override
        public void onCreate() {

            //在这个方法里面注册广播接收者
        //[1]获取ScreenReceiver实例
            receiver = new ScreenReceiver();

            //[2]创建IntentFilter对象
        IntentFilter filter = new IntentFilter();
        //[3]添加注册的事件
            filter.addAction("android.intent.action.SCREEN_OFF");
            filter.addAction("android.intent.action.SCREEN_ON");
            //[4]通过代码的方式注册
        registerReceiver(receiver, filter);

            super.onCreate();
    }

    //当服务销毁的时候调用
    @Override
    public void onDestroy() {

        //当actvivity销毁的时候  取消注册广播接收者 
        unregisterReceiver(receiver);


        super.onDestroy();
        }
    }`

(3)一定要记得配置service

5 为什么要引入bindService
目的为了调用服务里面的方法


创建前台Service
Service几乎都是在后台运行的,一直以来它都是默默地做着辛苦的工作。但是Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。当然有时候你也可能不仅仅是为了防止Service被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service,比如说墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息


public class MyService extends Service {  

    public static final String TAG = "MyService";  

    private MyBinder mBinder = new MyBinder();  

    @Override  
    public void onCreate() {  
        super.onCreate();  
        Notification notification = new Notification(R.drawable.ic_launcher,  
                "有通知到来", System.currentTimeMillis());  
        Intent notificationIntent = new Intent(this, MainActivity.class);  
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,  
                notificationIntent, 0);  
        notification.setLatestEventInfo(this, "Title", "Message",  
                pendingIntent);  
        startForeground(1, notification);  
        Log.d(TAG, "onCreate() executed");  
    }  

    .........  

} 

这里只是修改了MyService中onCreate()方法的代码。可以看到,首先创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章