Service和Thread的区别
既然是长耗时的操作,那么Thread也可以完成啊。没错,在程序里面很多耗时工作我们也可以通过Thread来完成,那么还需要Service干嘛呢?
- Service可以重写onStartCommand,使得Service被杀掉之后,Service能自动重启,Thread做不到。
- Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
Service与Activity怎么实现通信
- 通过Binder对象(AIDL):Activity调用bindService()方法,绑定一个继承Service的引用对象MyService。通过实例化ServiceConnection接口内部类监听的方法获取MyService中的Binder对象。如果想实现主动通知Activity的,还可以在MyService中添加回调方法。(例子代码如下)
- 通过广播:Activity调用registerReceiver(BroadcastReceiver recevier, IntentFilter filter)注册广播接收器,通过startService(Service service)启动一个集成Service的应用对象MsgService,之后MsgService可通过sendBoadcast(Intent intent)更新Actvity内容信息。
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public void startDownload() {
Log.d("MyService", "startDownload executed");
downloadCore();
} // 在Service中自定义startDownload方法,后续在Activity中调用此方法
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
} // 在Service中自定义getProgress方法,后续在Activity中调用此方法
public MyService getService() {
return MyService.this;
} // 在Service中自定义getService方法,后续在Activity中调用此方法,获得MyService对象以设置回调
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private void downloadCore() {
if (null != listener) {
listener.notifyProgress(0);
}
}
private OnProgressListener listener;
public void setOnProgressListener(OnProgressListener listener) {
this.listener = listener;
}
interface OnProgressListener {
void notifyProgress(int progress);
}
......
}
public class MainActivity extends AppCompatActivity {
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
MyService myService = downloadBinder.getService();
myService.setOnProgressListener(new MyService.OnProgressListener() {
@Override
public void notifyProgress(int progress) {
Log.d("MyService", "notifyProgress executed");
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bindServiceBtn = findViewById(R.id.button1);
Button stopServiceBtn = findViewById(R.id.button2);
bindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
});
stopServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
unbindService(connection);
}
});
}
}
Service的生命周期,两种启动方式(startService、bindService)的区别
- 被启动的服务的生命周期:如果一个Service被某个Activity调用Context.startService方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService方法多次启动,那么onCreate方法只会调用一次,onStartCommand将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。
- 被绑定的服务的生命周期:如果一个Service被某个Activity调用Context.bindService方法绑定启动,不管调用bindService调用几次,onCreate和onBind方法都只会调用一次(不调用unbindService),同时onStartCommand方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService断开连接或者之前调用bindService的Context不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。
- 被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStartCommand便会调用多少次。必须调用unbindService和stopService来停止服务。
- 当服务被停止时清除服务:当一个Service被终止(①调用stopService;②调用stopSelf;③不再有绑定的连接(没有被启动))时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程。
startService、bindService的区别:举一个简单的例子,最常用的Service就是音乐播放,如果你要startService的话,应用退出了,音乐还在播放。用bindService的话,程序退出了,音乐也就停了。
bindService和startService混合使用的生命周期以及怎么关闭
举两个混用的例子,未加粗的是Activity中的调用,加粗的是Service的生命周期:
- startService → onCreate → onStartCommand → bindService → onBind → stopService → unbindService → onUnbind → onDestroy
- bindService → onCreate → onBind → startService → onStartCommand → unbindService → onUnbind → stopService → onDestroy
只有当stopService和unbindService都被调用,Service才会调用onDestroy,Service的生命周期才会结束。
Service的onStartCommand方法有几种返回值?各代表什么意思?
在Service中重写onStartCommand方法,可以使得Service被杀死(比如杀掉apk)之后自动重启。
- START_STICKY 粘性的:如果Service被杀死之后,系统会自动重启该服务,但是不会保留之前传递过来的intent对象。
- START_NOT_STICKY 非粘性的:Service被杀死之后,系统不会自动重启该Service。
- START_REDELIVER_INTENT 重传intent:Service被杀死之后,系统会自动重启该服务,并且保留之前的intent传入(就是比START_STICKY多了一个intent)。
- START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但是不保证Service一定能重启。
IntentService是什么、原理、应用场景及其与Service的区别
- 是什么:如果直接把耗时操作放在Service的onStartCommand()中,很容易引起ANR。IntentService是继承于 Service 并处理异步请求的一个类,在IntentService内有一个子线程来处理耗时操作,通过 startService(intent)启动服务,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制或stopSelf()。
另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个子线程,执行完第一个再执行第二个,以此类推。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 1; i <= 20; i++) {
Intent intent = new Intent(this, MyIntentService.class);
startService(intent);
}
}
......
}
- 原理:IntentService本质是采用Handler & HandlerThread方式:(源码如下)
①通过HandlerThread单独开启一个名为IntentService的线程。
②创建一个名为ServiceHandler的Handler。
③把内部Handler与子线程HandlerThread的Looper进行绑定。
④通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent()。
⑤通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务。
注意:多次启动IntentService不会重新创建新的服务和新的线程,而是把消息加入消息队列中等待执行,而如果服务停止,会清除消息队列中的消息,后续的事件便不会执行。
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
- 应用场景:解决多个耗时任务需要顺序依次执行的问题。而如果仅用Service,开多个线程去执行耗时操作,就很难管理。例如排队下载,一个下载完的时候需要自动去下载下一个,下载完后自动关闭任务。
- 区别:
①IntentService是继承自Service类,创建了自己的特有方法onHandleIntent:每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,执行完第一个再执行第二个.
②每次IntentService执行完任务都会自动停止,而不需要我们手动去控制或stopSelf()。
③IntentService每次执行都开启一个子线程。(连续执行耗时操作除外)