Android四大组件之Service服务学习笔记(一)

Android四大组件之Service服务学习笔记(一)

  Service是安卓四大组件之一,服务是用在后台处理事情的,并且是不可见的,该服务不是我们所说的服务器的服务,他经常用来处理一些循环操作,但是它不同于子线程,服务是运行在主线程中的。
  服务一般分为本地服务和远程服务,这里先介绍本地服务。
  本地服务通常用两种启动方式
  1. 直接启动模式
    我们可以通过startService(Intent intent)方式去直接启动一个服务,对于intent意图,我们也可以用两种形式
  创建,一种是显示启动,一种是隐示启动,但是需要注意的是,在android5.0以后,所有的服务尽量通过显示
  意图来启动。否则就直接程序崩溃。所以建议都使用显示方式启动服务。如果一定要使用隐示启动方式, 则在对应的intent中添加一句intent.setPackage(对应服务所在的包名),通过这个方法,可以防止5.0后隐示启动发生崩溃的作用。下面通过代码来详细讲解下。 
MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Intent intent;

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

    }
    public void onClick(View view){
        intent = new Intent(this,MyService.class);
        //intent.setPackage("cn.itrealman.servicedemo");5.0以后需要加上这句代码
        switch (view.getId()) {
            case R.id.start:
                //启动服务
                startService(intent);
                break;
            case R.id.stop:
                //停止服务
                stopService(intent);
                break;        }
    }
}

在AndroidManifest.xml中配置Service

<service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <!--<intent-filter>-->
                <!--建议不用写,因为5.0后的系统不支持隐示启动-->
                <!--<action android:name="test.service" />-->
            <!--</intent-filter>-->
        </service>

MyService.java

public class MyService extends Service {
    public MyService() {
        Log.d("IT_Real", "MyService: 构造方法");
    }

    /**
     * 这个方法是通过绑定的方式才会调用该方法
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("IT_Real", "onBind: ");
        return null;
    }

    /**
     * 服务启动后初始化内部数据的方法,只会在第一次启动该服务的时候调用一次
     */
    @Override
    public void onCreate() {
        Log.d("IT_Real", "onCreate: ");
        super.onCreate();
    }

    /**
     * 销毁服务
     */
    @Override
    public void onDestroy() {
        Log.d("IT_Real", "onDestroy: ");
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("IT_Real", "onUnbind: ");
        return super.onUnbind(intent);
    }

    /**
     * 这个方法是直接启动服务时调用的方法,不过该方法已经过时了
     * 被下面的onStartCommand方法代替了
     * @param intent
     * @param startId
     */
    @Override
    public void onStart(Intent intent, int startId) {
        Log.d("IT_Real", "onStart: ");
        super.onStart(intent, startId);
    }

    /**
     * 这个方法也是直接启动服务时调用的方法
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("IT_Real", "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

}

在上面的代码中,当我们点击启动按钮时,相应的服务被启动,在此之前,我们先看一下直接启动方式服务的生命周期图:
                   这里写图片描述

在上面的图中,我可以了解到,当我们第一次启动服务时,会先调用onCreate()——>onStartCommand()——onStart(),然后服务会开始运行,直到调用stopService()方法才会停止服务,然后会调用相应的onDestory()方法,如果服务已经启动,我们多次点击启动服务按钮,则会多次掉用onStartCommand()——>onStart()方法

对于上面的这种方式,我们不会获取任何服务对象,也不能操作任何服务里面的数据,都是系统自己去操作的,加入说,我们的服务里面有一个doSth()方法,我想去调用这个方法做该事情,那么该怎么调用呢?这个时候,我们就只能去通过在onStartCommand()方法里面去调用了(在onStart()方法中也可以调用,但是不推荐这样使用,过时的方法我能不用就不用),代码如下:

 /**
     * 这个方法也是直接启动服务时调用的方法
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("IT_Real", "onStartCommand: ");
        //通过调用该方法
        doSth();
        return super.onStartCommand(intent, flags, startId);
    }
    private void doSth(){
        Log.d("IT_Real", "doSth: 我正在做某事...");
    }

这样我们就能完成需要操作的事情了,但是这样的操作往往会很不方便,不能很好的让用户去通过某种方式去操作,比如在播放音乐的时候,我们就会很难去控制服务去处理某些事情,所以一般我们会通过绑定的方式来启动服务。

  2. 绑定启动模式
  对于绑定启动服务,我们可以很好的获取到服务给我们返回的Ibinder对象,由于Ibinder是一个接口,通常我们会返回一个Ibinder的子类Binder对象。一般情况下,我们会去继承Binder对象,添加自己所需要的实现功能。绑定启动的方式是通过bindService(Intent intent, ServiceConnection conn, int flags)绑定服务,该方法的三个参数如下:
  intent:通过Intent指定要启动的服务
  conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与service之间的连接情况。当访问者与Service直接连接成功时将回调ServiceConnection对象的onServiceConnected(ComponentName name, IBinder service)方法,当Service所在的宿主进程由于异常中断或者其他原因终止,导致该Service与访问者之间断开连接时,会调用ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。
  flags:指定绑定时,是否通过自动创建Service(未创建的情况下),如果该参数指定0(不创建),或者写BIND_AUTO_CREATE(自动创建)
  创建代码如下:
MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Intent intent;
    private MyServiceConnection conn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        conn = new MyServiceConnection();

    }
    public void onClick(View view){
        intent = new Intent(this,MyService.class);
        switch (view.getId()) {
            case R.id.bindStart:
                bindService(intent,conn,BIND_AUTO_CREATE);
                break;
            case R.id.bindStop:
                unbindService(conn);
                break;        }
    }

    /**
     * ServiceConnection类,通过该类中的onServiceConnected方法
     * 中的IBinder service对象可以获取到绑定的服务对象中的MyBinder对象
     * 然后可以通过MyBinder对象中的getBindService方法获取我们的
     * MyBindService对象
     */
    class MyServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取Binder对象
            MyBindService.MyBinder service1 = (MyBindService.MyBinder) service;
            MyBindService service2 = service1.getBindService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

在AndroidManifest.xml中配置Service

 <service
        android:name=".MyBindService"
        android:enabled="true"
        android:exported="true">
 </service>

MyBindService.java

public class MyBindService extends Service {
    public MyBindService() {
    }

    /**
     * 返回的IBinder对象
     */
    class MyBinder extends Binder{
        public MyBindService getBindService(){
            returnMyBindService.this;
        }
    }

    @Override
    public void onCreate() {
        Log.d("IT_Real", "onCreate: ");
        super.onCreate();
    }

    /**
     * 绑定服务时调用该方法
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("IT_Real", "onBind: ");
        return new MyBinder();
    }


    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("IT_Real", "onUnbind: ");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.d("IT_Real", "onDestroy: ");
        super.onDestroy();
    }
}

这样我们就可以获取绑定服务对象了。然后我们看一下下面的生命周期图

                 这里写图片描述

通过绑定服务我们可以看出该生命周期。当调用了bindService方法时,生命周期为onCreate()——>onBind()——>服务运行,当调用unbindService()方法时,服务被关闭,执行onUnbind()——>onDestroy()
通过绑定服务,我们可以获取到对应的服务对象,如果说要实现某些操作,在服务里面定义对应的该操作,然后通过服务对象可以去调用该方法。我们去调用一个播放、暂停、上一首、下一首等。代码如下

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Intent intent;
    private MyServiceConnection conn;
    private MyBindService service2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        conn = new MyServiceConnection();

    }
    public void onClick(View view){
        intent = new Intent(this,MyBindService.class);
        switch (view.getId()) {
            case R.id.bindStart:
                bindService(intent,conn,BIND_AUTO_CREATE);
                break;
            case R.id.bindStop:
                unbindService(conn);
                break;
            case R.id.startMusic:
                //播放
                service2.start();
                break;
            case R.id.pause:
                //暂停
                service2.pause();
                break;
            case R.id.previous:
                //上一首
                service2.previous();
                break;
            case R.id.next:
                //下一首
                service2.next();
                break;

        }
    }

    /**
     * ServiceConnection类,通过该类中的onServiceConnected方法
     * 中的IBinder service对象可以获取到绑定的服务对象中的MyBinder对象
     * 然后可以通过MyBinder对象中的getBindService方法获取我们的
     * MyBindService对象
     */
    class MyServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取Binder对象
            MyBindService.MyBinder service1 = (MyBindService.MyBinder) service;
            service2 = service1.getBindService();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

MyBindService.java

public class MyBindService extends Service {
    public MyBindService() {
    }

    /**
     * 返回的IBinder对象
     */
    class MyBinder extends Binder{
        public MyBindService getBindService(){
            return MyBindService.this;
        }
    }

    /**
     * 服务被创建时调用该方法
     */
    @Override
    public void onCreate() {
        Log.d("IT_Real", "onCreate: ");
        super.onCreate();
    }

    /**
     * 绑定服务时调用该方法
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("IT_Real", "onBind: ");
        return new MyBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("IT_Real", "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 当调用了unbindService方法是,调用该方法
     * @param intent
     * @return
     */
    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("IT_Real", "onUnbind: ");
        return super.onUnbind(intent);
    }

    /**
     * 被关闭之前调用该方法
     */
    @Override
    public void onDestroy() {
        Log.d("IT_Real", "onDestroy: ");
        super.onDestroy();
    }

    public void start(){
        Log.d("IT_Real", "start: 播放");
    }
    public void pause(){
        Log.d("IT_Real", "pause: 暂停");
    }
    public void next(){
        Log.d("IT_Real", "next: 下一首");
    }
    public void previous(){
        Log.d("IT_Real", "previous: 上一首");
    }
}

这样就可以很好的操作服务里面的方法了。对于绑定服务,有一个地方需要注意,那就是,我们在启动服务后,如果退出了当前activity,或者结束该进程的时候,没有调用unbindService()方法,程序会报一个

Activity cn.itrealman.servicedemo.MainActivity has leaked ServiceConnectioncn.itrealman.service
demo.MainActivity$MyServiceConnection@6c1837b that was originally bound here
异常
这个异常表示连接已经绑定,我们没有解绑,会导致泄露问题。所以,一般我们建议在销毁Activity时,我们需要在Activity的onDestroy()方法中添加如下代码:

 @Override
    protected void onDestroy() {
        unbindService(conn);
        super.onDestroy();
    }

或者说,我们在关闭Activity之前,自己手动调用解绑方法。这样就能保证我们的程序不出错。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值