半个多月没写总结了,这段时间感觉学了不少东西,但是想总结一下却发现什么也没有。学习过程中没有目的性,见什么看什么,思来想去自己太浮躁,太心急。汇过来梳理一下发现还是有所补救。
android的SDK相关文档很重要,刚开始确实不知从何看起,也不觉得有多重要,最多就是出现没见过的类了,翻出来看看,但是了解了SDK文档的结构后就知道文档的重要性了。
1.service是什么
service是android的应用程序的四大组件之一,service是应用程序的一部分不与用户交互的后台操作的集合,同时也可以作为其他程序的被调用者来提供服务。它不是一个进程,它只是运行在主线程的一部分操作的集合。在activity,broadcast receiver,content provider之中,activity与service有最为相似,activity应该是学习android的过程中接触最多的部件,同样的,用户能够直观感受的就是activity,虽然在像播放音乐的时候service的参与能体会到,但是activity是最直接的,它承担着与用户交互的前台工作。而service则是后台数据处理。为什么和activity相似,个人理解在于,service和activity都是在主线程的运行的,从android的单线程安全的角度考虑,在service里面是可以进行UI操作的,同时这也意味这在service里面进行耗时的、耗资源的操作是不可取的。
说了那么多,就是:service可以作为程序的一个内部部件调用,也可以被其他应用程序调用;service是存在于主线程中的一部分操作的集合,可以进行UI操作,这也意味着不适合耗时的操作,以免阻塞主线程造成不好的用户体验。
2.service的调用方法
service和activity一样可以显示调用,也可以隐式调用。
1)显示调用只需要在intent中注明调用的service的class即可:(SDK中摘录的源代码)
Intent intent = new Intent(this, HelloService.class);
startService(intent);
2) 隐式调用,则是通过匹配响应的Intent-filter来完成:
Intent intent = new Intent();
intent.setAction(“我的服务的动作名称”);
.
.//设置相应的intentfilter匹配属性
.
startService(intent);
service的启动方式也有两种,startService()和bindService();上面说的显示和隐式调用都能通过startService()启动,至于能否通过bindService()启动,可以通过实验验证一下。
1)startService()方式启动service:
startService()方式只需要给一个Intent对象参数即可,此种方式启动的service会在后台一直运行,即使启动service的部件被销毁了,service依旧运行,直到service自身调用stopSelf()方法或者程序调用stopService()方法。通过startService()方式启动的service不能与其他应用程序进行通信,如果需要与应用程序通信,就需要通过bindService()方法启动,当然PendingIntent也可以做到与其他应用程序的沟通,详细看SDK文档。如果service是第一次调用,则会运行onCreate()函数,然后运行onStartCommand()函数,之后的每次启动只会调用onStartCommand()方法,也就是service本身存在的情况下,只调用onStartCommand()。前面已经说过service的销毁方法,值得注意的是stopSelfResult(int)形式的函数是匹配最近处理的intentId的情况下才会执行的函数。
2)bindService()方式启动service:
bindService较为复杂,不过其使用方式网上都有介绍,主要是理解connection中的IBinder和service中的Ibinder是同一个对象,绑定者和service通过这个binder进行通信。这个binder分别存在于connection的onServiceConnected()中和service的onBinder()中。第一次调用bindService()会执行onCreate()方法,然后是执行onBinder()方法,此时没有执行onStartCommand()方法。service会在绑定着销毁时,撤出绑定从而终止自身的生命周期,多个不同的应用程序可以同时绑定一个service,当service不在被绑定时,将销毁。
绑定时的应用程序通信,service会通过IBinder来完成,例如activity对象A和service对象S进行通信,则在S中定义一个内部Binder类B,用于封装一部分数据和操作,S在onBinder()方法中实现对B的初始化等相关操作,然后ruturn B。此时是调用bindService()方法后执行的onBinder()方法完成的操作。在对象A中,生成一个ServiceConnection对象SC,此时SC里面的onServiceConnected()有一个IBinder参数service,这个参数即为绑定的对象S的IBinder对象B。代码形式如下(SDK摘录):
Service对象:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
Activity对象:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
3.Service生成子线程:
service本身不能实现耗时操作,所以需要生成子线程来完成耗时操作,SDK提供了两种方式,一种是提供IntentService类来封装子线程的实现;一种是使用handle。
关于IntentService:1)会生成一个工作子进程,用于处理发送过来的intent。
2)创建一个工作队列,用于管理众多的intent对象,避免同时处理多个intent的发生。
3)提供默认的onBinder()接口,这就能实现绑定形式的进程通信。
4)当所有请求处理完后,将自行销毁service。
在IntentService中有接口函数onHandleIntent(),所有发送过来的intent都将会通过此函数生成子线程完成处理,用户只需要在该函数中实现自身定义的操作即可。可以看出IntentService是不能对UI进行操作,UI的单线程安全会组织其它线程的UI操作。
handle机制是通信机制,虽然有线程生成,但是其机制是可以用于UI操作,这个在多线程和异步操作中有介绍。
4.Service在manifest.xml中的声明和优先级
Servie和activity一样,需要在manifest中进行声明,器本身也有很多属性设置,可以参看SDK文档的介绍。Service可能被系统kill,就如同activity被kill一样,service也有其优先级,在SDK可以找到相应的优先级划分。