Service

本文copy自全面简洁Service讲解,仅仅用于个人加深印象

Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有UI界面,是在后台运行的组件。
Service是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。
Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。


生命周期

  • 官方说明图


  • 生命周期方法具体介绍
    主要介绍内部调用方法 & 外部调用方法的关系。



    4个手动调用的方法
    startService() 启动服务
    stopService() 关闭服务
    bindService() 绑定服务
    unbindService() 解绑服务
    5个自动调用的方法
    onCreat() 创建服务
    onStartCommand() 开始服务
    onDestroy() 销毁服务
    onBind() 绑定服务
    onUnbind() 解绑服务

  • 常见的生命周期使用


类型

按照运行地点分类

  • 本地服务
    特点:运行在主线程,主进程被终止后,服务也会终止
    优点:节约资源,通信方便,由于在同一进程因此不需要IPC和AIDL
    缺点:限制性大,主进程被终止后,服务也会终止
    应用:需要依附某个进程的服务,最常用的服务类型,如音乐播放
  • 远程服务
    特点:运行在独立进程,服务常驻在后台,不受其他Activity影响
    优点:灵活,服务常驻在后台,不受其他Activity影响
    缺点:消耗资源,单独进程,使用AIDL进程IPC复杂
    应用:系统级别服务

按照运行类型分类

  • 前台服务
    特点:在通知栏显示通知,用户能看到。
    应用:服务使用时需让用户知道并进行相关操作等,如音乐播放器,服务被终止时,通知栏的通知也会消失
  • 后台服务
    特点:处于后台的服务,用户无法看到
    应用:服务使用时不需要用户知道或进行相关操作,如天气更新,日期同步。服务被终止时,用户无法知道

按照功能分类

  • 不可通信的后台服务
    特点:用startService()启动,调用者退出后Service仍然存在
    应用:服务不需要与Activity&Service通信
  • 可通信的后台服务
    1)
    特点:用bindService() 启动,调用者退出后,随着调用者销毁。
    应用:服务需要与Activity&Service通信,需控制服务开始时刻。
    2)
    特点:使用startService(),bindService()启动,调用者退出后,随着调用者销毁。
    应用:服务需要与Activity&Service通信,不需要控制服务开始时刻。(服务一开始就运行)

使用讲解

本地Service

这是最普通、最常用的后台服务Service。

  • 步骤1:新建子类继承Service类
    需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法
public class MyService extends Service {
//启动Service之后,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑
//由于这里作Demo用,所以只打印一些语句
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("执行了onCreat()");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("执行了onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("执行了onDestory()");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
  • 步骤2:构建用于启动Service的Intent对象
  • 步骤3:调用startService()启动Service、调用stopService()停止服务
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button startService;
    private Button stopService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService = (Button) findViewById(R.id.startService);
        stopService = (Button) findViewById(R.id.stopService);
        startService.setOnClickListener(this);
        startService.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            //点击启动Service Button
            case R.id.startService:
                //构建启动服务的Intent对象
                Intent startIntent = new Intent(this, MyService.class);
                //调用startService()方法-传入Intent对象,以此启动服务
                startService(startIntent);
            //点击停止Service Button
            case R.id.stopService:
                //构建停止服务的Intent对象
                Intent stopIntent = new Intent(this, MyService.class);
                //调用stopService()方法-传入Intent对象,以此停止服务
                stopService(stopIntent);
        }
    }
}
  • 步骤4:在AndroidManifest.xml里注册Service
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="scut.carson_ho.demo_service">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        //注册Service服务
        <service android:name=".MyService">
        </service>
    </application>
</manifest>

Androidmanifest里Service的常见属性说明

属性                      说明                                        备注
android:name              Service的类名    
android:label             Service的名字                               若不设置,默认为Service类名
android:icon              Service的图标    
android:permission        申明此Service的权限                          有提供了该权限的应用才能控制或连接此服务
android:process           表示该服务是否在另一个进程中运行(远程服务)     不设置默认为本地服务;remote则设置成远程服务
android:enabled           系统默认启动                                 true:Service 将会默认被系统启动;不设置则默认为false
android:exported          该服务是否能够被其他应用程序所控制或连接        不设置默认此项为 false
可通信的服务Service

上面介绍的Service是最基础的,但只能单机使用,即无法与Activity通信
接下来将在上面的基础用法上,增设“与Activity通信”的功能,即使用绑定Service服务(Binder类、bindService()、onBind()、unbindService()、onUnbind())

  • 步骤1:在新建子类继承Service类,并新建一个子类继承自Binder类、写入与Activity关联需要的方法、创建实例
public class MyService extends Service {

    private MyBinder mBinder = new MyBinder();
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("执行了onCreat()");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("执行了onStartCommand()");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("执行了onDestory()");
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("执行了onBind()");
        //返回实例
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("执行了onUnbind()");
        return super.onUnbind(intent);
    }
    //新建一个子类继承自Binder类
    class MyBinder extends Binder {
        public void service_connect_Activity() {
            System.out.println("Service关联了Activity,并在Activity执行了Service的方法");
        }
    }
}
  • 步骤2:在主布局文件再设置两个Button分别用于绑定和解绑Service
  • 步骤3:在Activity通过调用MyBinder类中的public方法来实现Activity与Service的联系
    即实现了Activity指挥Service干什么Service就去干什么的功能
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button startService;
    private Button stopService;
    private Button bindService;
    private Button unbindService;
    private MyService.MyBinder myBinder;

    //创建ServiceConnection的匿名类
    private ServiceConnection connection = new ServiceConnection() {
        //重写onServiceConnected()方法和onServiceDisconnected()方法
        //在Activity与Service建立关联和解除关联的时候调用
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
        //在Activity与Service解除关联的时候调用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //实例化Service的内部类myBinder
            //通过向下转型得到了MyBinder的实例
            myBinder = (MyService.MyBinder) service;
            //在Activity调用Service类的方法
            myBinder.service_connect_Activity();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService = (Button) findViewById(R.id.startService);
        stopService = (Button) findViewById(R.id.stopService);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        bindService = (Button) findViewById(R.id.bindService);
        unbindService = (Button) findViewById(R.id.unbindService);

        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.startService: //点击启动Service
                Intent startIntent = new Intent(this, MyService.class); //构建启动服务的Intent对象
                startService(startIntent);//调用startService()方法-传入Intent对象,以此启动服务
                break;
            case R.id.stopService:   //点击停止Service
                Intent stopIntent = new Intent(this, MyService.class);  //构建停止服务的Intent对象
                stopService(stopIntent); //调用stopService()方法-传入Intent对象,以此停止服务
                break;
            case R.id.bindService:   //点击绑定Service
                Intent bindIntent = new Intent(this, MyService.class);    //构建绑定服务的Intent对象
                bindService(bindIntent,connection,BIND_AUTO_CREATE);  //调用bindService()方法,以此停止服务
                //参数说明
                //第一个参数:Intent对象
                //第二个参数:上面创建的Serviceconnection实例
                //第三个参数:标志位
                //这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service
                //这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行
                break;
            case R.id.unbindService: //点击解绑Service
                unbindService(connection); //调用unbindService()解绑服务,参数是上面创建的Serviceconnection实例
                break;
                default:
                    break;
        }
    }
}
前台Service

前台Service和后台Service(普通)最大的区别就在于:

  1. 前台Service在下拉通知栏有显示通知(如下图),但后台Service没有;
  2. 前台Service优先级较高,不会由于系统内存不足而被回收;后台Service优先级较低,当系统出现内存不足情况时,很有可能会被回收
    用法很简单,只需要在原有的Service类对onCreate()方法进行稍微修改即可
@Override
    public void onCreate() {
        super.onCreate();
        System.out.println("执行了onCreat()");

        //添加下列代码将后台Service变成前台Service
        //构建"点击通知后打开MainActivity"的Intent对象
        Intent notificationIntent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);

        //新建Builer对象
        Notification.Builder builer = new Notification.Builder(this);
        builer.setContentTitle("前台服务通知的标题");//设置通知的标题
        builer.setContentText("前台服务通知的内容");//设置通知的内容
        builer.setSmallIcon(R.mipmap.ic_launcher);//设置通知的图标
        builer.setContentIntent(pendingIntent);//设置点击通知后的操作

        Notification notification = builer.getNotification();//将Builder对象转变成普通的notification
        startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来

    }
远程Service

Android:远程服务Service(含AIDL & IPC讲解)

使用场景

通过上述描述,你应该对Service类型及其使用非常了解;
那么,我们该什么时候用哪种类型的Service呢?
各种Service的使用场景请看下图:


其他补充

  1. Service 与 Thread的区别
  • 结论:Service 与 Thread 无任何关系
  • 之所以有不少人会把它们联系起来,主要因为Service的后台概念
    后台:后台任务运行完全不依赖UI,即使Activity被销毁 / 程序被关闭,只要进程还在,后台任务就可继续运行
  • 关于二者的异同


  • 一般会将 Service 和 Thread联合着用,即在Service中再创建一个子线程(工作线程)去处理耗时操作逻辑,如下代码
@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
//新建工作线程
    new Thread(new Runnable() {  
        @Override  
        public void run() {  
            // 开始执行后台任务  
        }  
    }).start();  
    return super.onStartCommand(intent, flags, startId);  
}  
class MyBinder extends Binder {  
    public void service_connect_Activity() {  
  //新建工作线程
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 执行具体的下载任务  
            }  
        }).start();  
    }  
}  
  1. Service和IntentService的区别
    具体请看文章:Android多线程:IntentService用法&源码
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容