Service的学习

Service

可以在后台长时间运行操作而不提供用户界面的组件。

组件可以启动服务,也可以绑定到服务。

服务可以处理网络事务,播放音乐,io操作,ContentProvider交互 等耗时操作都在后台执行。

服务在其托管进程的主线程中执行。(即不创建自己的线程,也不在单独的进程中执行(除非另外指定))

耗时操作应该在服务内创建新线程来工作。

使用Service 还是 使用线程来完成后台任务

服务是一种即使用户未与应用交互也可以在后台运行的组件。因此必要时才去创建服务。(比如:用户不管处于哪个app的哪个activity,都期望后台有此功能)

如果只是在用户正在与应用交互时,才有此需要,则应创建新线程,而非服务。例如,开发者只想在activity运行的同时,播放一些音乐。

托管Service的进程,相比托管Activity(启动线程的)的进程,有更高的进程优先级。服务被kill的机会更小。

两种形式的Service

Context.startService

一旦启动便在后台无限期运行,即使启动服务的组件已经销毁也不受影响

已启动的服务通常是执行单一的操作。

Context.bindService

当应用组件通过调用bindService后绑定到服务。

Context.startService方式启动服务

执行startService,生命周期执行的是

继续执行两次startService


执行stopService,生命周期是


在onStartCommand中做一些耗时的操作


onStartCommand在主线程执行,

代码

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        logs("onStartCommand , thread " + Thread.currentThread().getName());
        return super.onStartCommand(intent, flags, startId);
    }

打印


因此onStartCommand中不适合做一些耗时的操作,若使用耗时的操作,应该开启一个线程。

启动一个耗时Service的例子

启动service后,开启一个线程,用来做耗时的操作,等耗时操作完毕,使用handler发送消息给主线程,通知service关闭。

package com.jue.testservice1;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by jue on 2016/11/17.
 */

public class MyService extends Service {

    private Handler mHander = new MyHandler();

    @Override
    public void onCreate() {
        super.onCreate();
        logs("onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        logs("onStartCommand , thread " + Thread.currentThread().getName() + " 开启线程,做一些耗时的操作");

        new MyThread().start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        logs("onDestroy");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        logs("onBind");
        return null;
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        logs("onRebind");
    }

    @Override
    public boolean onUnbind(Intent intent) {
        logs("onUnbind");
        return super.onUnbind(intent);
    }

    private void logs(String txt) {
        Log.i("jue","MyService -> " + txt);
    }

    public class MyThread extends Thread {
        @Override
        public void run() {

            logs("MyThread-> run 一些耗时的操作 开始");
            try{
                Thread.sleep(16000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            logs("MyThread-> run 一些耗时的操作 结束,给主线程发送消息,通知Service关闭");
            mHander.sendEmptyMessage(0);
        }
    }

    public class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            logs("MyHandler-> handleMessage 收到消息,执行stopSelf,结束");
            stopSelf();
        }
    }

}

输出日志


onStartCommand的返回值

START_STICKY

如果service 进程在started之后(after returning from onStartComand),被kill。稍后,系统将re-create Service,并且会保证在新的servcie实例创建好后,调用onStartComand方法。开发者应该谨慎使用,如果没有等待的命令被传递到这个service,调用时,将传递一个null intent对象。

这个常量清楚的表明了service可能会在任意时间开启,停止。比如一个后台的音乐被重放。

START_NOT_STICKY

如果被kill掉 并且没有新的intent来启动,那么这个service不会被 re-create,直到再次被显示的调用Context.startService

START_REDELIVER_INTENT

如果被kill掉,最后一次被启动的intent将被再次传递到onStartComand方法。

START_STICKY_COMPATIBILITY

在被系统kill之后,不保证onStartComand将会再次被调用。

多次执行start与stop

启动已经存在的service,只会执行一次onCreate,会执行多次onStartCommand,

即便多次启动,也只需要执行一次stopService,即可stop掉

下面日志的代码执行了多次startService,执行了多次stopService


Context.startService之后,停止一个Service

启动的Service会一直保持运行。

主动停止Service

其他组件:Context.stopService.

Service自身:Service.stopSelf()

Context.bindService 何时使用

如需与Activity 和 Service进行交互

需要通过ipc向其他应用公开某些功能,则应该创建bind服务。

绑定Service的特点:

必须实现onBind回调方法,以返回IBinder,用于定义与服务通信

如果没有组件绑定到service,系统会销毁service。

多个客户端可以同时绑定到服务。

客户端完成与service交互后,需要取消绑定。一旦没有客户端绑定到该service,系统就会销毁service

多个service可以同时绑定到一个服务。但是只有第一个客户端绑定时,才会调用onBind

Activity 、Service、ContentProvider 可以绑定到服务。BroadcastReceiver不能绑定服务。

onServiceDisconnected 系统在与服务的连接意外中断时调用该方法,比如当前服务崩溃或被终止。当客户端取消绑定时,系统不会调用该方法。

绑定的service无法使用Context.stopService停止。

绑定的service无法使用Service.stopSelft停止。

开发者应该捕获DeadObjectException异常,在连接中断的时引发,这是远程调用的唯一异常

当服务与所有client的绑定全部取消时,系统会销毁服务。(除非还使用onStartCommand启动了该服务)

对于使用startService启动的service,必须显示的停止service。 stopService 或 stopSelf

创建绑定service,必须提供IBinder

有三种方法定义接口

  1. 继承自Binder类
    • 同一进程中,优先使用此方式。
    • 不以此方式创建接口的唯一原因:服务被启动应用占用 或 不同进程占用
  2. 使用Messenger
    • 跨进程工作
    • 无需使用AIDL即可执行IPC通信
    • 使用Messenger会在单一线程中包含所有请求的队列,这样就不必对服务进行线程安全设计了
  3. 使用AIDL

如何解除bind 的service

Context.unbindService

同一进程中,继承Binder实现绑定Service的实现代码

 BindService代码

public class BindService extends Service {

    private Binder localBinder = new LocalBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return localBinder;
    }

    public class LocalBinder extends Binder {

        public BindService getService() {
            return BindService.this;
        }
    }

    public int getRandomInt() {
        logs("getRandomInt ...............  bindService.hashCode= " + hashCode());
        new Throwable().printStackTrace();
        return new Random().nextInt(100);
    }

    public static void logs(String text) {
        Log.i("jue","BindService  -> " + text);
    }
}

与其交互的activity的代码

    @Override
    public void onClick(View v) {
        if (v == mStart) {
            Intent intent = new Intent(MainActivity.this, MyService.class);
            startService(intent);
            return;
        }

        if (v == mStop) {
            Intent intent = new Intent(MainActivity.this, MyService.class);
            stopService(intent);
            return;
        }

        if (v == mStartIS) {
            logs("onClick start MyIntentService ");
            Intent intent = new Intent(MainActivity.this, MyIntentService.class);
            startService(intent);
            return;
        }

        if (v == mBind) {
            bindBindService();
            return;
        }
        if (v == mBindGet) {
            getDataFromService();
            return;
        }

        if (v == mUnbind) {
            unBindService();
            return;
        }

    }

    private void getDataFromService() {
        if (!isBind) {
            logs("getDataFromService 还没有绑定,return");
            return;
        }
        logs("getDataFromService");
        int data = mBindService.getRandomInt();
        mTextView.setText("来自Service的数据: " + data);
    }

    private void bindBindService() {
        if (isBind) {
            logs("bindService, 已经bind,return");
            return;
        }

        logs("bindService");
        Intent intent = new Intent(MainActivity.this, BindService.class);
        bindService(intent, connection, BIND_AUTO_CREATE);

    }

    private void unBindService() {
        if (!isBind) {
            logs("unBindService, 已经unbind,return");
            return;
        }
        logs("unBindService");
        unbindService(connection);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            isBind = true;
            BindService.LocalBinder lb = (BindService.LocalBinder) service;
            mBindService = (BindService) lb.getService();
            logs("ServiceConnection->onServiceConnected   bindService.hashCode= " + mBindService.hashCode());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBind = false;
            logs("ServiceConnection->onServiceDisconnected");
        }
    };

输出日志


可以得知:

主线程中调用的实例就是BindService的实例。通过binder,获取到service实例,对其进行了直接调用。

继承Binder方式,并不合适跨进程,如果声明单独的进程

        <service android:name=".BindService" android:process=":testprocess" />

发生异常的日志


Activity与Service 使用Messenger跨进程发送消息

首先看下Messenger的代码实现

public final class Messenger implements Parcelable {
    private final IMessenger mTarget;


    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
    

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
    

    public IBinder getBinder() {
        return mTarget.asBinder();
    }

    。。。省略代码

    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}
即知

  1. 通过handler可以创建Messenger
  2. 通过IBinder可以创建Messenger
  3. Messenger可以发送消息
  4. getBinder可以返回IBinder类型

MessengerService代码如下

public class MessengerService extends Service {

    private Messenger mainMessenger;

    private Messenger serviceMessenger = new Messenger(new IncomingHandler());


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        logs("onBind");
        return serviceMessenger.getBinder();
    }

    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            logs("IncomingHandler->handleMessage , 我们要向Activity发送消息了");
            Toast.makeText(MessengerService.this, "MessengerService->handleMessage", Toast.LENGTH_LONG).show();

            mainMessenger = msg.replyTo;

            Message msg2 = Message.obtain();

            try {
                mainMessenger.send(msg2);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }
    }

    public void logs(String text) {
        Log.i("jue","MessengerService -> " + text);
    }

}
通过上面代码可知:

  1. Service通过Handler创建了Messenger
  2. onBind方法返回的是Messenger.getBinder()
  3. 在Service中得到消息之后,通过Messge.replyTo获得了activity线程的messenger

Activity代码

public class MessengerActivity extends AppCompatActivity implements View.OnClickListener {

    private boolean mIsBind;

    private Messenger mServiceMessenger;

    private TextView mTitle;
    private Button mBind;
    private Button mUnBind;
    private Button mDataGet;

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

        mTitle = (TextView) findViewById(R.id.top0);
        mBind = (Button) findViewById(R.id.bind);
        mUnBind = (Button) findViewById(R.id.bund);
        mDataGet = (Button) findViewById(R.id.get_bind);

        mBind.setOnClickListener(this);
        mUnBind.setOnClickListener(this);
        mDataGet.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        if (mBind == v) {
            bindService();
            return;
        }

        if (mUnBind == v) {
            unbindService();
            return;
        }

        if (mDataGet == v) {
            getDataFromService();
            return;
        }

    }

    private void unbindService() {
        if (!mIsBind) {
            logs("onClick -> unbindService 已经解除绑定,return");
            return;
        }
        logs("onClick -> unbindService");
        unbindService(connection);
    }

    private void bindService() {
        if (mIsBind) {
            logs("onClick -> bindService 已经绑定,return");
            return;
        }

        logs("onClick -> bindService");
        Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    public void getDataFromService() {
        logs("onClick -> getDataFromService");
        Message msg = Message.obtain();
        msg.replyTo = mMainMessenger;
        try {
            mServiceMessenger.send(msg);
        } catch (Exception e) {

        }
    }

    public ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mIsBind = true;
            mServiceMessenger = new Messenger(service);
            logs("ServiceConnection -> onServiceConnected ");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mIsBind = false;
            logs("ServiceConnection -> onServiceDisconnected ");
        }
    };

    public static void logs(String text) {
        Log.i("jue","MessengerActivity-> " + text);
    }

    private Messenger mMainMessenger = new Messenger(new MyHandler());

    private class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            mTitle.setText("我们收到了来自跨进程service的消息");
        }
    }
}

Activity中

  1. 当service connected时,使用ibinder对象创建了Messenger。
  2. 使用Service的Messenger发送消息时,通过设定Message.replyTo来传递当前进程的Messenger给Service.

当向MessengerService发送多个耗时的消息时,MessengerService的收到的消息会依次执行。

public class MessengerService extends Service {

    private Messenger mainMessenger;

    private Messenger serviceMessenger = new Messenger(new IncomingHandler());


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        logs("onBind");
        return serviceMessenger.getBinder();
    }

    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            logs("IncomingHandler->handleMessage " + msg.what + " , thread[" + Thread.currentThread().getName() + "]  start ");

            try {
                Thread.sleep(12000);
            } catch (Exception e) {

            }

            logs("IncomingHandler->handleMessage " + msg.what + " , thread[" + Thread.currentThread().getName() + "]  end ");

        }
    }

}
log输出

bindService中, onRebind方法的调用

Android文档的图


onRebind执行的条件

  1. Service 被startService启动了,但未被销毁。
  2. Service被startService启动后,执行了bindServcie,unBindService,并且Service的onUnbind 返回true。
  3. 步骤1,2后,再次执行了bindService






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值