很高兴能再次遇见您——service

  • 只有 Activity、服务和内容提供程序可以绑定到服务 — 您无法从广播接收器绑定到服务。

1:Service和Thread的区别

  • service也是在主线程中运行的,因此在执行密集型或者阻止型操作的时候,还是需要在service中是通过线程来操作,比如播放音乐或者访问网络。

  • 在google文档中分析了service和子线程之间的应用区别,service主要是当用户未与应用交互也可在后台运行,而子线程呢,则主要是当用户与应用交互。比如同样是播放音乐,如果需求是当用户不与应用交互的情况下仍然要播放,那就是service,如果仅仅是在打开activity的时候播放,那么用子线程就可以。

2:Service的回调方法

(1):onStartCommand()
  • 当使用startService()来启动service,那么就回调用该方法。一旦调用该方法,service就会无限期执行。想要结束就需要调用stopSelf()/stopService(intent)。如果只想绑定服务,无需实现该方法。这里的stopService(intent)是在context中的方法context.stopService(intent),在其他组件中调用。如果使用的是重载方法stopSelf(startId)这里的startid需要与最后一个startid相等,否则不会关闭。
  • 三个返回方法:start_redeliver_intent(重建,上一个intent开始调用onstartcommand,挂起的itnent依次传递);start_sticky(重建,不会传递上一个intent,如果有挂起则依次传递,如果没有,则用空intent调用onstartcommand);start_not_sticky(除非有挂起intent,否则不重建);
(2):onBind()
  • 如果不希望被绑定,返回null即可

  • 如果希望绑定,那么就必须返回一个IBinder接口。

(3):onCreate()
  • 首次创建才会调用,调用在onStartCommand()和onBind()之前。非首次创建不调用
(4):onDestory()
  • service接收的最后一个回调。

3:xml中的属性

  • android:exported=false 表示当前这个service只能用于当前应用。其他应用无论显示隐式都不能使用。如果不设置的话,默认值会因为是否含有过滤器而改变。因为添加了过滤器意味着想要外部调用,那么这个值如果不设置,默认为true,如果没有过滤器,默认值就是false

  • 如果想要设置intent-filter,那么在代码中同时还要设置setPackage()。

  • enable,默认为true,是否允许系统创建实例

4:IntentService

  • 创建默认的工作线程,用于在应用的主线程外执行传递给 onStartCommand() 的所有 Intent。

  • 创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样您就永远不必担心多线程问题。

  • 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。

  • 提供 onBind() 的默认实现(返回 null)。

  • 提供 onStartCommand() 的默认实现,可将 Intent 依次发送到工作队列和 onHandleIntent() 实现。

  • 综上所述,您只需实现 onHandleIntent() 来完成客户端提供的工作即可。(不过,您还需要为服务提供小型构造函数。)

  public HelloIntentService() {
      super("HelloIntentService"); //必须调用,传入一个工作线程的名字
  }

5:通过HandlerThread模拟IntentService

intentservice的特点就是有一个子线程按照顺序依次执行请求,全部请求执行完成,就会自动关闭服务。模拟的关键就在于两点:
其一:子线程按照顺序依次执行,这个需求交给了handlerthread。通过获取这个handlerthread的looper,创建一个handler,依次传递任务。
其二:因为每次请求都会调用onstartcommand,而这个方法每次调用的参数startid是不一样的,因此在每次任务结束之后就会调用以下stopself(startID)来模拟,当所有任务完成就关闭服务。

(1):在onCreate方法中创建HandlerThread,和Handler。因为onCreate只会在创建时被调用一次.
  • 创建HandlerThread
HandlerThread handlerThread=new HandlerThread(MyIntentService.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
  • 创建Handler
myHandler=new MyHandler(handlerThread.getLooper());
……
private final class MyHandler extends Handler{
        public MyHandler(Looper looper){
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            try {
                name=msg.getData().getString("name");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                Log.e(MyIntentService.class.getSimpleName(),"InterruptedException");
                Thread.currentThread().interrupt();
            }
            Log.e(MyIntentService.class.getSimpleName(),name+":"+msg.arg1);
            //the startId matches the last start request and the service will be stopped
            stopSelf(msg.arg1);
        }
    }

(2):重写onStartCommand
  • Messager.obtain()和myHandler.obtainMessage()两者的区别在于后者绑定了message的target为这个handler,前者没有。
 @Override
    public int onStartCommand(Intent intent,  int flags, int startId) {
//        Message obtain = Message.obtain();
        name=intent.getStringExtra("name");
        Log.e(MyIntentService.class.getSimpleName(),name+"---->onStartCommand");
        Message message = myHandler.obtainMessage();
        message.arg1=startId;
        if(intent !=null){
            message.setData(intent.getExtras());
        }
        myHandler.sendMessage(message);
        return START_STICKY;
    }

6:通过PendingIntent.getBroadCast()让普通Service与调用者通信。

  • 创建一个启动receiver的intent。receiver还是需要自己自定义。
  • 将这个启动receiver的intent放进PendingIntent.getBroadCast()的参数中。
  • 将这个pendingIntent作为一个变量,通过启动service的intent传递到service中bundle.putParcelable("receiver",pIntent);
  • 在service中需要发送消息的时候调用。需要发送的消息还是通过创建一个新的intent来传递。
PendingIntent client = bundle.getParcelable("receiver");  
Intent intent=new Intent();
intent.putExtra("param",name);
client.send(intent);

7:服务的三种运行方式

  • 启动服务,无限期运行,需要调用stopSelf或者stopService.重复开启,只会重复调用onStartCommand
  • 绑定服务,所有绑定者都退出(unbindService()),service销毁.重复绑定,不会重复调用onBind
  • 启动且绑定服务。先启动再绑定。就算所有绑定者都退出,还是需要调用stopSelf或者stopService才能销毁。如果还有一个绑定者未退出,那么就算调用了停止service方法,也没有用。
  • 也就是说只要调用了onStartCommand方法,服务就回无限期运行,就必须手动调用stopSelf/stopService停止
  • startService-->onCreate-->onStartCommand->onDestroy
  • bindService-->onCreate-->onBind-->onUnbind()-->onDestroy
  • stop停止service,并不会引起service的相关回调,而unbindService则会引起回调onUnbind

8:绑定服务

跨进程通信必须要绑定服务才能实现

(1):三种接口定义

  • 扩展Binder类。如果服务只是您的自有应用的后台工作线程,不需要跨进程,则优先采用这种方法。

LocalService.java

public class LocalService extends Service {
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        LocalService getService() {
            return LocalService.this;
        }
    }

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

    public int getRandomNumber() {
      return  new Random().nextInt(100);
    }
}

BindingActivity.java

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    ...

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }


    public void onButtonClick(View v) {
        if (mBound) {
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

onServiceDisconnected()
Android 系统会在与服务的连接意外中断时(例如当服务崩溃或被终止时)调用该方法。当客户端取消绑定时,系统“不会”调用该方法。如果您的服务已启动并接受绑定,则当系统调用您的 onUnbind() 方法时,如果您想在客户端下一次绑定到服务时接收 onRebind() 调用,则可选择返回 true。onRebind() 返回空值,但客户端仍在其 onServiceConnected() 回调中接收 IBinder。

很高兴能再次遇见您——service_第1张图片

  • 使用Messenger。

服务在多进程不同应用间使用的时候。Messenger会在单一线程中创建包含所有请求的队列,也就是服务会一个一个按顺序完成请求。不必考虑多线程安全。关于Messenger的使用可以参看Messenger的例子。该例子介绍了,当服务绑定成功之后,acitvity发送一条消息到服务,服务回一条消息到activity。接下来用户每点击一次activity中的按钮发送消息到service,service都会自动回一条消息到activity。

  • 使用AIDL。

Messenger也是以AIDL为底层结构,虽然说AIDL和Messenger都是服务于不同进程应用的,但是二者的区别在于,Messenger是单线程队列完成请求,有顺序,每次只完成一个。AIDL则是多线程,服务同时处理多个请求,需要考虑线程安全。

你可能感兴趣的:(很高兴能再次遇见您——service)