前言
Service是四大组件中的一员,它属于逻辑计算型的组件,往往在后台做逻辑处理。本文整理了Service相关的知识点:
startService
1.创建Service,写一个类继承Service,重写onCreate,onStartCommond,onBind方法,在AndroidManifest.xml文件里配置。
2.启动Service,使用Intent启动,如下:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
3.第一次startService(),执行方法顺序:
onCreate->onStartCommond
之后无论再次startService(),只会执行onStartCommond方法,也就是onCreate只执行一次。
4.销毁Service:调用stopService()即可。
bindService
当我们需要Service和Activity进行通讯的时候,就可以将Activity和Service绑定。
1.关联Service,代码如下:
MyService
public class MyService extends Service {
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class MyBinder extends Binder {
public void down() {
Log.d("TAG", "down");
}
}
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.down();//调用onBind()里的方法
}
};
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
这里我们首先创建了一个ServiceConnection的匿名类,在里面重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在Activity与Service建立关联和解除关联的时候调用。在onServiceConnected()方法中,我们又通过向下转型得到了MyBinder的实例,有了这个实例,Activity和Service之间的关系就变得非常紧密了。现在我们可以在Activity中根据具体的场景来调用MyBinder中的任何public方法,即实现了Activity指挥Service干什么Service就去干什么的功能。bindService需要传入三个参数,第一个参数就是刚刚构建出的Intent对象,第二个参数是前面创建出的ServiceConnection的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。
2.解绑Service:调用unBindService()即可。
3.销毁Service:由于在关联Service的时候指定的标志位是BIND_AUTO_CREATE,说明点击Bind Service按钮的时候Service也会被创建。如果只调用stopService和unbindService中的一个是无法销毁的,必须是两个方法都调用,解释如下:
stopService只会让Service停止,unbindService只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。
前台Service
Service一般都是在后台运行的,但是后台Service的优先级比较低,在系统内存不足的时候,很可能被系统Kill掉。如果我们想要提高Service的优先级,不妨使用前台Service。前台Service在通知栏会一直有显示,如墨迹天气。使用如下:
@Override
public void onCreate() {
super.onCreate();
Notification notification = new Notification(R.drawable.ic_launcher,
"有通知到来", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容",
pendingIntent);
startForeground(1, notification);
Log.d(TAG, "onCreate()");
}
我们首先创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。
Service与Thread
1.初学Android的时候,我也会问‘Service和Thread到底什么关系?’,其实这两者是完全没有关系的。我们需要理解,Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。
2.Service是运行在主线程的,我们可以通过如下代码证实:
MainActivity的onCreate()方法
Log.e("MainActivity", "MainActivity thread id is " + Thread.currentThread().getId());
MyService的onCreate()方法
Log.E("MyService", "MyService thread id is " + Thread.currentThread().getId());
我们会发现,打印出来的值是一样的。也就是我们在Service里不要做耗时操作,反之同样会出现“ANR”。
远程Service
在上面,我们提到,如果在Service里做耗时操作会导致’ANR’,那么我们只需要另起线程去做耗时任务即可。当然也可以使用IntentService,参照我的另一篇博文Android IntentService详解。下面来看看远程Service,用法很简单,如下:
<service
android:name="com.example.servicetest.MyService"
android:process=":remote" >
</service>
我们只需要在配置文件里为Service配置process属性即可。此时,我们在Service里做耗时操作,并不会’ANR’了。原因是我们的Service现在已经处于另一个进程了,它只会阻塞该进程中的主线程,并不会影响到我们的主程序。
1.此时的Service,如果我们直接调用bindService,那么就会直接崩溃。原因是我们的Activity和Service已经处于不同的进程里,按照之前的方式是无法建立关联了。
2.如需跨进程让Service和Activity关联。则需要使用到跨进程通讯Aidl。这个会在我的另一篇文章进行整理。