- 只有 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。
- 使用Messenger。
服务在多进程不同应用间使用的时候。Messenger会在单一线程中创建包含所有请求的队列,也就是服务会一个一个按顺序完成请求。不必考虑多线程安全。关于Messenger的使用可以参看Messenger的例子。该例子介绍了,当服务绑定成功之后,acitvity发送一条消息到服务,服务回一条消息到activity。接下来用户每点击一次activity中的按钮发送消息到service,service都会自动回一条消息到activity。
- 使用AIDL。
Messenger也是以AIDL为底层结构,虽然说AIDL和Messenger都是服务于不同进程应用的,但是二者的区别在于,Messenger是单线程队列完成请求,有顺序,每次只完成一个。AIDL则是多线程,服务同时处理多个请求,需要考虑线程安全。