很好用的两个东西,知其然知其所以然
首先注意:服务并不是一个新的进程,启动的应用程序在哪个进程,服务就在哪个进程
-IntentService作为Service的升级版,增加了在服务中使用线程的能力,而Service其实的在主线程中运行的,耗时操作的话还是会引起ANR,IntentService的好处就不言而喻了,不仅能处理耗时操作,而且优先级还比线程高,同时服务执行完成后还会自动停止。接下来我们从源码角度去探究下这些功能如何实现。
首先打开IntentService
源码不多我就全贴出来:
- 首先可以看到是继承自Service
- 然后内部包裹了一层HandlerThread
- 创建服务的同时把handler与HandlerThread 绑定
任务就会在HandlerThread 中执行
注意:任务是在MessageQueue中被Looper不断的取出来由Handler去执行的
所以一次只能执行一个任务,IntentService并不能并发执行任务
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
// onHandleIntent在这里处理任务信息,处理完了后调用stopSelf服务就自动停止了
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
//这里要注意,不是说一个请求结束后,服务就停止了,因为可能service会接收到新的启动请求,stopSelf有个参数startId,跟最后启动该service时生成的ID相等时才会执行停止服务。
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
// 可以看到在服务创建的时候,这里创建了HandlerThread,并且把一个Handler和这个HandlerThread绑定了起来(通过传入线程的Looper)
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
//每次调用startService都会调用这个方法,于是消息就会被发送到ServiceHandler那里去处理,就是个HandlerThread 线程了
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
// 销毁服务的时候退出循环,其实就是结束了这个线程
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
// 这个是用来和Activity通信的
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
顺便写一下HandlerThread的使用方式
HandlerThread handlerThread = new HandlerThread("name");
// 开启start就是把HandlerThread 内部的Looper启动起来,详见下方源码
handlerThread.start();
// 接下来只要把循环器对象给Handler 就可以完成绑定了
// 不然默认Handler是用主线程的Looper,当然如果是更新UI,我们可以在线程中用这个handler发送消息,然后handler的回调方法会在主线程中运行,就能实现异步请求更新UI了
Handler handler = new Handler(handlerThread.getLooper());
// 这里发消息就会把任务发送处理队列,Looper会不断取出Runnable交由Handler处理
handler.post(new Runnable() {
@Override
public void run() {
}
});
HandlerThread 继承Thread,内部有一个Looper,调用start()会启动这个循环器
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Service和Activity的通信
还记得Service中的那个onBind()方法吗,我们需要让它返回一个IBinder对象,并在Activity中拿到这个对象
// Service中创建一个内部类
public class DownLoadBinder extends Binder{
public void startDownLoad(){
System.out.println("=====startDownLoad()=====");
}
public void getProgress(){
System.out.println("=====getProgress()=====");
}
}
// 这个方法返回
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
System.out.println("=====onBind=====");
return downLoadBinder;
}
在Activity中这样调用
private ServiceConnection connection=new ServiceConnection() {
/**
* 服务解除绑定时候调用
*/
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
/**
* 绑定服务的时候调用
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
//myService=((DownLoadBinder) service).
downLoadBinder=(DownLoadBinder) service;
/*
* 调用DownLoadBinder的方法实现参数的传递
*/
downLoadBinder.startDownLoad();
downLoadBinder.getProgress();
}
};
接下来就简单了,调用绑定服务方法
Intent bindIntent = new Intent(this, MyService.class);
// 第三个参数是一个标记,表明一旦建立绑定就创建服务,会执行onCreate,但不会执行OnStartCommand
bindService(bindIntent, connection, BIND_AUTO_CREATE);
// 记得要关闭
unbindService(connection);
关于服务关闭的问题:
只调用bindService和unbindService可以启动/关闭服务(没有调用startService)
但是如果调用了startService和bindService那么关闭服务就必须同时调用stopService和unbindService