一、什么是Service?
Service是一个可以在后台长时间运行操作而且没有用户界面的组件。它是运行在主线程中的,所以不能在Service中执行耗时操作。它可以由其他组件来启动,比如activity或者broadcast,服务一旦启动,就会一直在后台运行,即使启动它的组件被销毁了,也不会影响它的运行。我们可以把service和activity进行绑定,这样就可以实现两者之间的数据交互。
二、service和thread的区别?
- 定义:thread是程序运行的最小单元,我们可以通过开启子线程来完成一些耗时操作,而service是后台服务,是安卓中的一种机制,如果是本地的service,那么它就运行在它所在的主线程,所以service中不能进行耗时操作。
- 实际开发:不能在service中进行耗时操作,如果一定要进行,那么也必须要开启子线程,那为什么不在activity中开启子线程呢?因为activity很难对子线程进行把控,一旦activity销毁了,那么将很难获得子线程的实例,容易造成内存泄漏。而service不一样,即使activity被销毁了,service依然可以在后台执行。
- 应用场景:如果我们需要进行耗时操作,那么就必须要开启子线程。而service是需要长时间在后台运行,并且不需要用户界面的情况下才会使用,比如后台播放音乐,天气预报的统计等。
三、service的两种启动方式以及区别?
- startService:通过此种方式启动的服务,会一直在后台运行,除非手动关闭。
- 执行步骤如下:
- 1、定义一个类继承service;
- 2、在manifest.xml文件中注册service;
- 3、使用context的startService()启动服务;
- 4、如果不再使用,调用stopService()方法来停止该服务。
- bindService:此时service和activity处于绑定状态,两者之间可以进行数据交互。
- 执行步骤如下:
- 定义一个服务端继承service,并且在类中实现IBinder接口的实例对象,并提供公共方法给客户端调用;
- 在onBind()方法中返回此Binder实例;
- 客户端在onServiceConnected()方法中接收Binder实例,并通过服务端提供的方法绑定服务。
接下来通过代码来深刻理解两种启动service的方法到底什么区别。
- 首先是startService
public class StartService extends Service {
private static final String TAG = "StartService";
/**
* 首次创建服务时,系统将调用此方法执行一次性设置程序(在调用onStartCommand()或者onBind()之前),
* 如果服务已在运行,则不会调用此方法,该方法只被调用一次。
*/
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "StartService Thread id is ==="+Thread.currentThread().getId() );
}
/**
* 绑定服务的时候才会调用
* 必须要实现的方法
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* 每次通过startService()启动Service时都会被回调。
* @param intent
* @param flags
* @param startId
* @return return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
* 如果返回START_STICKY,那么在系统内存空暇时,系统会尝试重新启动服务,而此时的intent为null;
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("onStartCommand invoke");
Log.e(TAG, "StartService Thread id is ==="+Thread.currentThread().getId() );
return super.onStartCommand(intent, flags, startId);
}
/**
* 服务销毁时的回调
*/
@Override
public void onDestroy() {
System.out.println("onDestroy invoke");
super.onDestroy();
}
}
- 1
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button mBtStop,mBtStart,mBtBind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtStart= (Button) findViewById(R.id.btn_start);
mBtStop= (Button) findViewById(R.id.btn_stop);
Log.e(TAG, "MainActivity thread id is=="+Thread.currentThread().getId() );
final Intent intent=new Intent(MainActivity.this,StartService.class);
mBtStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(intent);
}
});
mBtStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(intent);
}
});
}
}
- 1
-接下来是bindService
public class BindService extends Service {
private static final String TAG = "BindService";
private LocalBinder binder=new LocalBinder();
private int count;
private Thread thread;
private boolean quit;
/**
* 创建Binder对象,返回给客户端的Activity使用,提供数据交接的接口
*/
public class LocalBinder extends Binder{
//申明一个方法getService(),提供给客户端调用
BindService getService(){
//返回当前对象LocalBinder,这样我们就可以在客户端调用Service的公共方法了。
return BindService.this;
}
}
/**
* 把Binder类返回给客户端
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "Service is invoke Created" );
thread =new Thread(new Runnable() {
@Override
public void run() {
while (!quit){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
});
thread.start();
}
@Override
public void onDestroy() {
Log.e(TAG, "Service is invoke Destroyed" );
this.quit=true;
super.onDestroy();
}
/**
* 公共方法
* @return
*/
public int getCount(){
return count;
}
/**
* 解除绑定时调用
* @param intent
* @return
*/
public boolean onUnbind(Intent intent){
Log.e(TAG, " Service is invoke onUnbind" );
return super.onUnbind(intent);
}
}
- 1
public class BindActivity extends AppCompatActivity {
private static final String TAG = "BindActivity";
private Button btnBind,btnUnBind,btnGetDatas;
private BindService mService;
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bind);
btnBind= (Button) findViewById(R.id.btn_Bind);
btnUnBind= (Button) findViewById(R.id.btn_UnBind);
btnGetDatas= (Button) findViewById(R.id.btn_GetDatas);
//创建绑定对象
final Intent intent=new Intent(this,BindService.class);
//开启绑定
btnBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "绑定调用:bindService" );
bindService(intent,conn, Service.BIND_AUTO_CREATE);
Log.e(TAG, "绑定成功");
}
});
//解除绑定
btnUnBind.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "解除绑定调用:unbindService" );
if(mService!=null){
mService=null;
unbindService(conn);
}
}
});
//获取数据
btnGetDatas.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mService!=null){
//通过绑定服务传递的Binder对象,获取Service暴露出来的数据
Log.e(TAG, "从服务器获取数据 "+mService.getCount() );
}else {
Log.e(TAG, "还没有进行绑定,请先绑定");
}
}
});
/**
* ServiceConnection代表与服务器的连接,它只有两个方法
* @param savedInstanceState
*/
conn=new ServiceConnection(){
/**
* 与服务器交互的接口方法,绑定服务的时候被回调,在这个方法中获取绑定Service 传递过来的IBinder对象
* 通过这个IBinder对象,实现宿主与Sevice的交互
* @param name
* @param service
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "绑定成功调用 onServiceConnected");
BindService.LocalBinder binder= (BindService.LocalBinder) service;
mService=binder.getService();
}
/**
* 当取消绑定的时候被回调,但正常情况下式不会被回调的,只有当Service服务被意外销毁时
* 例如内存不足时这个方法才会被自动调用
* @param name
*/
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "绑定失败调用 onServiceDisconnected");
}
};
}
}