Android四大组件之服务的两种启动方式详解

Service简单概述

Service(服务):是一个没有用户界面、可以在后台长期运行且可以执行操作的应用组件。服务可由其他应用组件启动(如:Activity、另一个service)。此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。例如:服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而这一切均可在后台进行。


进程的优先级

了解进程的优先级可以帮助你理解服务~

  • 1. Foreground process(前台进程)

    • 一句话总结:当前跟用户有交互的进程就是前台进程。
  • 2. Visible process(可见进程)

    • 相当于Activity的onPause方法执行。如:Activity弹出Dialog时。
  • 3. Service process(服务进程)

    • 相当于使用startService开启一个服务,虽然做的事情用户看不到,但是又是用户所关心的事情。如:后台播放音乐,下载数据等。
  • 4. Background process(后台进程)

    • 相当于Activity的onStop方法被执行。如:按Home键退出应用。
  • 5. Empty process(空进程)

    • 应用程序没有任何的组件在活动,该应用就是一个空进程。唯一存活的原因就是为了提高下次开启的时间。

开启服务的两种方式

服务:默认运行在主线程。

服务的创建流程

  1. 自定义一个服务类继承 android.app.Service;
  2. 在清单文件中配置 service(AndroidManifest.xml);
  3. 在服务类中重写方法。
<service android:name=".service.MyCustomService"></service>

服务的两种开启方式

一:start 方式

先上代码

    private Intent startIntent;
    //start方式:开启服务
    public void startOpenService(View v) {
        //创建一个开启服务的Intent对象
        startIntent = new Intent(this, MyCustomService.class);
        this.startService(startIntent); //开启一个服务
    }

    //start方式:关闭服务
    public void startCloseService(View v) {
        if (startIntent != null) {
            this.stopService(startIntent);
            startIntent = null;
        }
    }

1. 通过 startService(Intent service)开启服务

  • onCreate()、onStartCommand() 两个方法在服务第一次开启的时候会被依次执行。
  • 当服务开启之后,再点击开启服务,只会执行onStartCommand()方法。

2. 通过 stopService(Intent service)关闭服务

  • onDestroy() 方法会在执行 stopService 方法(关闭服务)的时候,被执行!
  • 注意参数:Intent对象不能为null,要先进行判空(不为null的情况下,可以多次调用)。

特别说明
1. stopService传入的Intent对象,必须和startService传入的Intent对象是同一个对象,才能保证开启的服务被关闭。
2. 应用退出后(应用在后台运作,未被杀死),服务依然会运行中。
3. 当手动杀掉应用进程后,服务将会终止!且该方式不会执行服务的onDestroy()方法。

二:bind 方式

先上代码

    private Intent bindIntent;
    private MyServiceConnection connection;
    private boolean isSuccess;
    //bind方式:开启服务
    public void bindOpenService(View v) {
        if (!isSuccess) {
            bindIntent = new Intent(this, MyCustomService.class);
            //boolean bindService(Intent service,  //开启服务的意图对象
            //                    ServiceConnection conn, //服务连接对象
            //                    int flags)  //绑定服务操作选项()
            connection = new MyServiceConnection();
            isSuccess = this.bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
        }
    }
    
    //bind方式:解绑服务
    public void bindCloseService(View v) {
        //void unbindService(ServiceConnection conn)
        if (connection != null) {
            this.unbindService(connection);
            connection = null;
            isSuccess = false;
        }
    }

1. 通过 bindService() 开启服务

  • onCreate()、onBind() 两个方法在服务第一次开启的时候,被依次执行。
  • 再次操作bindService的话,不会有什么方法被执行。若要使用该方式开启服务的话,建议获取绑定后的状态,若成功则不再操作绑定。

2. 通过 unbindService() 解绑服务

  • onUnbind()、onDestroy() 两个方法会在执行服务解绑 unbindService 方法的时候,被依次执行。所以解绑只能操作一次。

特别说明
1. 绑定和解绑传递的ServiceConnection对象要保证是同一个对象!
2. isSuccess存储服务绑定成功(true)的状态,当绑定成功之后,避免重复的绑定。因为每次bindService传递的ServiceConnection对象都是new的新对象,unbindService传递的ServiceConnection对象可能会与服务绑定时传递的对象不一致,就会抛出异常!
3. 解绑之后,isSuccess赋值false,就可以再次操作绑定了。
4. bind方式开启的服务是一个隐形的服务,在设置中无法找到(其实现在有些手机定制系统,start方式开启的服务也成了一个隐形服务了)。
5. bind方式开启服务与开启者(Activity),存在着依附关系,在开启者被销毁前,必须解绑bind方式开启的服务,不然会抛出异常!(不求同生,但求同死。)


服务模板代码

需求:在Activity中,使用 bind方式 启动一个服务,并调用服务中的方法(模拟一些业务处理)。
分析:流程步骤

  1. 创建一个服务类,继承 Service。如:MyCustomService;
  2. 自定义一个服务接口对象类,实现ServiceConnection接口。如:MyServiceConnection;
  3. 自定义一个中间帮助类,继承Binder类(IBinder实现类)。当服务中的onBind方法被执行的时候,作为返回值。如:MyBinderImpl;
  4. 自定义一个接口,封装一些中间帮助类对象共有的函数。如:MyBinderInterface。

整个流程代码如下

MyCustomService.class

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
/**
 * 创建一个服务类
 */
public class MyCustomService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        //该方法:在使用【bind绑定】的方式:开启服务的时候,才会被调用
        Log.e("Service生命周期", "【onBind】");
        //返回值需要一个IBinder接口实现类对象(可以返回自定义实现类对象)
        return new MyBinderInter();
    }
    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("Service生命周期", "【onUnbind】");
        return super.onUnbind(intent);
    }


    @Override
    public void onCreate() {
        super.onCreate();
        //服务第一次创建时调用
        Log.e("Service生命周期", "【onCreate】");
        //获取服务运行线程
        String name = Thread.currentThread().getName();
        long id = Thread.currentThread().getId();
        Log.e("线程", "【Service】" + name + "-" + id);
    }
    
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //每次开启服务(Activity内调用startService()方法)时调用
        Log.e("Service生命周期", "【onStartCommand】");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        //服务被销毁时调用
        Log.e("Service生命周期", "【onDestroy】");
    }
    
    

    //模拟:定义一些函数,作为业务处理
    public void playPoker() {
        Toast.makeText(this, "玩扑克", Toast.LENGTH_SHORT).show();
    }

    public void playBall() {
        Toast.makeText(this, "打球", Toast.LENGTH_SHORT).show();
    }


    /**
     * 中间帮助类:自定义类继承 Binder(IBinder 接口实现类)
     */
    public class MyBinderInter extends Binder implements MyBinderInterface {

        @Override
        public void callPlayPoker() {
            playPoker();
        }

        @Override
        public void callPlayBall() {
            playBall();
        }
    }
}

MyServiceConnection.class

import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
/**
 * 创建一个服务接口对象类:当服务绑定成功时,可以接收一个中间帮助类对象
 * 当 MyCustomService 中的 onBind 方法返回值不为null时,该服务连接对象类中的方法才会被执行
 */
public class MyServiceConnection implements ServiceConnection {

    private MyCustomService.MyBinderInter myBinderInter;

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        //服务绑定成功后执行(onBind执行后执行该方法)  IBinder:中间帮助类对象
        this.myBinderInter = (MyCustomService.MyBinderInter) iBinder;
        Log.e("Service生命周期", "【onServiceConnected】");
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        //该方法在连接正常关闭的情况下不会被执行,只有在Service被破坏或杀死的情况下执行。
        //如:系统资源不足,需要杀掉该服务,则会执行该方法。
    }

    public void callPlayPoker(){
        if(myBinderInter!=null){
            myBinderInter.callPlayPoker();
        }
    }

    public void callPlayBall(){
        if(myBinderInter!=null){
            myBinderInter.callPlayBall();
        }
    }
}

接口:MyBinderInterface

//自定义接口:封装中间帮助类所共有的一些方法
public interface MyBinderInterface {
    //随意定义两个抽象方法,由实现类重写
    void callPlayPoker();
    void callPlayBall();
}

ServiceActivity 内调用服务内的方法

  • 切记:在activity执行onDestroy()方法的时候,解绑服务,否则会抛出异常。
public class ServiceActivity extends BaseActivity {

    private Intent bindIntent;
    private MyServiceConnection connection;
    private boolean isSuccess;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service);
    }

    //bind方式:开启服务
    public void bindOpenService(View v) {
        if (!isSuccess) {
            bindIntent = new Intent(this, MyCustomService.class);
            connection = new MyServiceConnection();
            isSuccess = this.bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
        }
    }

    public void playPoker(View v) {
        if (connection != null) {
            connection.callPlayPoker();
        }
    }

    public void playBall(View v) {
        if (connection != null) {
            connection.callPlayBall();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (connection != null) {
            this.unbindService(connection);
            connection = null;
            isSuccess = false;
        }
    }
}


关于:bindService和unbindService的源码说明(英文好的小伙伴可以一起学习)
boolean bindService (Intent service, ServiceConnection conn, int flags)

  • 方法说明
    Connect to an application service, creating it if needed. This defines a dependency between your application and the service. The given conn will receive the service object when it is created and be told if it dies and restarts. The service will be considered required by the system only for as long as the calling context exists. For example, if this Context is an Activity that is stopped, the service will not be required to continue running until the Activity is resumed.
    This function will throw SecurityException if you do not have permission to bind to the given service.
    Note: this method can not be called from a BroadcastReceiver component. A pattern you can use to communicate from a BroadcastReceiver to a Service is to call startService(Intent) with the arguments containing the command to be sent, with the service calling its stopSelf(int) method when done executing that command. See the API demo App/Service/Service Start Arguments Controller for an illustration of this. It is okay, however, to use this method from a BroadcastReceiver that has been registered with registerReceiver(BroadcastReceiver, IntentFilter), since the lifetime of this BroadcastReceiver is tied to another object (the one that registered it).
  • Parameters(参数说明)
    service:Identifies the service to connect to. The Intent may specify either an explicit component name, or a logical description (action, category, etc) to match an IntentFilter published by a service.
    conn:Receives information as the service is started and stopped. This must be a valid ServiceConnection object; it must not be null.
    flags:Operation options for the binding. May be 0, BIND_AUTO_CREATE, BIND_DEBUG_UNBIND, BIND_NOT_FOREGROUND, BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, or BIND_WAIVE_PRIORITY.
  • Returns(返回值说明)
    If you have successfully bound to the service, true is returned; false is returned if the connection is not made so you will not receive the service object.

void unbindService (ServiceConnection conn)

  • 方法说明
    Disconnect from an application service. You will no longer receive calls as the service is restarted, and the service is now allowed to stop at any time.
  • Parameters(参数说明)
    conn:The connection interface previously supplied to bindService(). This parameter must not be null.

参考链接:Google官方文档:Service

PS:期待与大家有更多的交流,谢谢~

posted @ 2019-09-22 11:39  ming3  阅读(1670)  评论(0编辑  收藏  举报