什么是Service?
Service即服务,是Android四大组件之一,主要用于在后台处理一些计算型的任务。如后台播放音乐等。但是service是在主线程中的,所以耗时任务处理需要在service中开启子线程的。
Service的特点:
1. 它无法与用户直接进行交互、它必须由用户或者其他程序显式的启动;
2. 它的优先级比较高,它比处于前台的应用优先级低,但是比后台的其他应用优先级高;
Service的分类:
本地服务:这种服务主要依附于主进程上,因此不需要IPC,也不需要AIDL。在主进程被杀后服务会终止。如音乐软件的播放等。
远程服务:这种服务是在独立的进程上,对应进程名格式为所在包名加上你指定的android:process字符串。如一些提供系统服务的Service,这种Service是常驻的。
Service 与 Thread 的区别: 请记住这句话:半毛钱关系都没有。一般用service并在其中处理耗时任务,是因为便于控制。
service的生命周期:
startService方式启动的服务:onCreate(),onStartCommand,onDestroy()。
bindService方式绑定的服务:onCreate(),onBind(),onUnbind(),onDeatroy()。
使用service的方式有启动和绑定两种方式。一个service可以既被启动也可以被绑定。若是关闭这种服务,需要调用stopService和unbindService方法解绑并关闭service,与调用的顺序无关。
注意:
1. 一个已经启动的服务,再次启动只会重复执行onStartCommand方法。
2. 一个已经绑定的服务,再次绑定,生命周期内方法均不会被执行。
3. 停止服务的时候,只需要一次stopService或unbindService即可(若既启动有绑定,需要两个方法都要调用)。
如何使用service
清单文件注册(四大组件中除了广播,都需要在AndroidMainfest.xml中注册)
<application>
...
<service android:name=".FirstService"/>
...
</application>
startService方式启动的service类
public class SecondService extends Service {
private static String TAG = "SecondService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
}
bindService方式绑定的service类
public class FirstService extends Service {
private static String TAG = "FirstService";
private MyBinder myBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return myBinder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
class MyBinder extends Binder {
public void downloadTask() {
//这里仍是在主线程内,所以若是做耗时操作,需要开启子线程去完成
Log.d(TAG, "downloadTask");
}
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
}
activity内调用如下
public class SecondActivity extends Activity {
private static String TAG = "SecondActivity";
@BindView(R.id.startService)
Button startService;
@BindView(R.id.stopService)
Button stopService;
@BindView(R.id.bindService)
Button bindService;
@BindView(R.id.unbindService)
Button unbindService;
private FirstService.MyBinder myBinder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
Log.d(TAG, "onCreate");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(TAG, "onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d(TAG, "onRestoreInstanceState");
}
@OnClick({R.id.startService, R.id.stopService, R.id.bindService, R.id.unbindService})
public void onClick(View view) {
switch (view.getId()) {
case R.id.startService:
startService(new Intent(this, FirstService.class));
break;
case R.id.stopService:
stopService(new Intent(this, FirstService.class));
break;
case R.id.bindService:
bindService(new Intent(this, FirstService.class), serviceConnection, BIND_AUTO_CREATE);
break;
case R.id.unbindService:
unbindService(serviceConnection);
break;
}
}
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (FirstService.MyBinder) service;
myBinder.downloadTask();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
stopService(new Intent(this, FirstService.class));
Log.d(TAG, "onDestroy");
}
}
上面已经列出了不同启动的方式和使用方法。如activity内:
一般startService方式启动的service是放任服务执行任务的,交互较少。而bindService方式绑定的service,交互较多。
bindService方式绑定一个service如下:
bindService(new Intent(this, FirstService.class), serviceConnection, BIND_AUTO_CREATE);
这里BIND_AUTO_CREATE表示绑定后自动创建服务。还有很多标志位,查阅源码即知~
serviceConnection是一个内部类,其中:
onServiceConnected方法表示绑定后的回调,onServiceDisconnected是解绑后的回调。
我们通过onServiceConnected内的向下转型获得binder实例,然后可以调用service内MyBinder的方法downloadTask()。
myBinder = (FirstService.MyBinder) service;
myBinder.downloadTask();
MyBinder内还有其他的方法通过此实例被activity调用,这也是activity与service通信的一种方式。
activity与service的通信
上面的是一种通信方式,是一种被动式通信。若实现service主动向activity通信,还有以下方式~
1. 接口回调
2. 广播
注意:从不用EventBus,因可读性差,不便维护~
案例:每秒从service发送进度给activity,并更新在activity的textview上。
接口回调方式建立通信:
public interface OnProgressListener {
void onProgress(int progress);
}
在service内,接口定义写在MyBinder内了,保持低耦合(一个binder类可以复用在不同的service中哦),其他的是无关代码,省略~
...
public class MyBinder extends Binder {
private OnProgressListener onProgressListener;
public void setOnProgressListener(OnProgressListener onProgressListener) {
this.onProgressListener = onProgressListener;
}
public void downloadTask() {
//这里仍是在主线程内,所以若是做耗时操作,需要开启子线程去完成
Log.d(TAG, "downloadTask");
new Thread(new Runnable() {
@Override
public void run() {
while (flag && count < 20) {
try {
Thread.sleep(1000);
count++;
onProgressListener.onProgress(count);
Log.d(TAG, "onStartCommand=" + count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
...
activity内接受数据更新在Textview上:
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (FirstService.MyBinder) service;
myBinder.downloadTask();
myBinder.setOnProgressListener(new OnProgressListener() {
@Override
public void onProgress(final int progress) {
Log.d(TAG,"onProgress="+progress);
runOnUiThread(new Runnable() {
@Override
public void run() {
showProgress.setText("onProgress="+progress);
}
});
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
runOnUiThread底层也是通过handler异步通信机制的,此类知识点可看
http://blog.youkuaiyun.com/abcjinzi/article/details/53433320
广播方式建立通信: 很简单的,会用广播就会了,省略了吧~
个人分述:一般情况下,在同一时刻,服务是一对一与activity交互的,使用接口回调方式通信更方便,广播适合同时刻一对多的情况,而其他情况下都有种“大材小用”的感觉~
接下来还有对service的进一步研究,敬请期待~