「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」
上一篇文章,我们介绍了Android开发的四大组件中的Activity,今天我们来介绍四大组件中的第二组件Service。
Service的基本认识
Service是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件.Service可由其他应用组件启动,而且即使用户切换到其他应用,Service仍将在后台继续运行.Service主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务.必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。
Service和Activity很相似,但是区别在于:Service一直在后台运行,没有用户界面,所以不会到前台,如果Service被启动起来,就和Activity一样,具有自己的声明周期.另外,需要注意的是,Service和Thread不是一个意思,不要被Service的后台概念所迷惑.实际上Service并不会自动开启线程,所有的代码都是默认运行在主线程中的.因此,我们需要在Service的内部手动创建子线程,并在这里执行具体的任务,否则可能造成ANR的问题.
Service的使用方式
一、Started(启动的)
当应用组件(如 Activity)通过调用 startService() 启动Service时,Service即处于“启动”状态.一旦启动,Service即可在后台无限期运行,即使启动Service的组件已被销毁也不受影响.通常,一个开启的Service执行单一操作并且不会给调用者返回结果.例如,它可能通过网络下载或上传文件.操作完成后,Service会自行停止运行。
二、Bind(绑定的)
当应用组件通过调用 bindService() 绑定到Service时,Service即处于“绑定”状态.一个绑定的Service提供客户端/服务器接口允许组件和Service交互,甚至跨进程操作使用进行间通信(IPC),仅当与另一个应用组件绑定时,绑定服务才会运行.多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
Started Service的使用
Started(启动的)
创建一个类继承Service:
public class MyService extends Service {
/**
* 该方法是Service子类必须实现的方法,该方法可返回一个IBinder对象,可用于其他组件与service组件相互通信
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* service重新绑定时并且在onUnbind方法返回true的情况下能够执行回调此方法
* @param intent
*/
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
/**
* service第一次创建后立即创建回调的方法
*/
@Override
public void onCreate() {
super.onCreate();
Log.e("MyService", "onCreate");
}
/**
* 其他组件每次调用startService(intent),此方法便会执行一次,用于其他组件向service传值,返回值的设置又能控制自身的重启情况。早期版本是onStart(),现已经过时
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("MyService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/**
* Service关闭之前将会调用该方法
*/
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* service解除绑定断开连接时调用该方法。
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
在清单文件中注册Service:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService" />
</application>
好了,下面我们写一个类来启动service:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnStartService, btnStopService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
btnStartService.setOnClickListener(this);
btnStopService.setOnClickListener(this);
}
private void initView() {
btnStartService = (Button) findViewById(R.id.start);
btnStopService = (Button) findViewById(R.id.stop);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start:
startService(startIntent);
break;
case R.id.stop:
stopService(stopIntent);
break;
default:
break;
}
}
}
点击上面开始按钮可以看到,打印了onCreate和onStartCommand两个方法,这时候再点击开始服务的话,日志里只有onStartCommand,Service只有在第一次启动的时候才会调用onCreate()方法,此后再次点击Start Service按钮只会执行onStartCommand()方法,并不会再启动一个服务。
Bind Service的使用
创建一个BindService:
public class BindService extends Service {
private int count=0;
private boolean isQuit=false;
//定义getService方法返回的对象
public MyBind myBind=new MyBind();
//创建Binder子类
public class MyBind extends Binder{
public int getCount() {
return count;
}
public BindService getService() {
return BindService.this;
}
}
//Service子类必须实现的方法,绑定该Service时回调的方法
@Override
public IBinder onBind(Intent intent) {
return myBind;
}
//Service被创建是调用该方法
@Override
public void onCreate() {
System.out.println("Service is Created.");
//创建并启动一个线程,动态修改count变量值
new Thread(){
@Override
public void run() {
while (!isQuit) {
try {
Thread.sleep(1000);//使得当前线程休眠1000毫秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count++;
}
}
}.start();
super.onCreate();
}
//在所有onUnbind被回调之后调用
@Override
public void onDestroy() {
System.out.println("Service is Destroyed.");
isQuit=true;
super.onDestroy();
}
//定义一个返回实例名的方法
public String getDemoName() {
return "Service实例";
}
//在所有与Service绑定的客户端都解除绑定之后被回调
@Override
public boolean onUnbind(Intent intent) {
System.out.println("Service is Unbind.");
return true;//表示下次客户端绑定的时候接受一个onRebind()的调用(而不是调用 onBind())
}
}
同样也要在清单里注册哈,这里就不贴代码了,下面看下bind在初始化使用:
public class BindServiceActivity extends Activity {
private Button btnBind,btnUnBind;
private BindService bindService;
private MyBind myBind;
private boolean isBind=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bind);
btnBind=(Button)findViewById(R.id.btnBind);
btnUnBind=(Button)findViewById(R.id.btnUnBind);
OnClickListener listener=new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnBind:
Intent intent=new Intent(BindServiceActivity.this,BindService.class);//显示启动Service
//绑定指定的Service
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
isBind=true;
break;
case R.id.btnUnBind:
if (isBind) {
//解除绑定Service
unbindService(serviceConnection);
isBind=false;
bindService=null;
Toast.makeText(BindServiceActivity.this,"--Service is Unbind.--"
, Toast.LENGTH_LONG).show();
}else {
Toast.makeText(BindServiceActivity.this,"--你还未绑定Service--"
, Toast.LENGTH_LONG).show();
}
break;
}
}
};
btnBind.setOnClickListener(listener);
btnUnBind.setOnClickListener(listener);
}
//定义一个ServiceConnection对象
private ServiceConnection serviceConnection=new ServiceConnection() {
//当Activity与Service通过非UnBind()方法断开连接的时候回调该方法
@Override
public void onServiceDisconnected(ComponentName name) {
bindService=null;
Toast.makeText(BindServiceActivity.this,"--Service UnConnected.--"
, Toast.LENGTH_LONG).show();
}
//当Activity与Service连接成功的时候回调该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取getService()方法返回的BindService对象
myBind=((MyBind)service);
bindService=myBind.getService();
Toast.makeText(BindServiceActivity.this,"--Service Connected.--"
, Toast.LENGTH_LONG).show();
System.out.println("--Service Connected.--");
}
};
}
当我点击“绑定service”按钮,可以看到控制台打印“Service is Created.”与“--Service Connected.--”的输出。当该Activity中绑定该Service之后,该Activity还可以通过MyBind对象获取Service的运行状态,当我点击“获取Service状态”按钮,看到界面弹出的提示信息。如果我们单击“解除绑定”按钮,即可看到LogCat中的输出信息:“Service is Unbind.”,“Service is Destroyed.”,当程序调用unbindService()方法解除对某个Service的绑定时,系统会先回调Service的unbindService()方法,然后回调onDestory()方法。
区别:
与多次调用startService()方法启动Service不同的是,多次调用bindService()方法并不会重复绑定。在这个实例中不管用户单击“绑定Service”对少次,系统只会回调Service的onBind()方法一次。
下面我们来看下2中不同启动Service过程中的生命周期变化:
对比上面的图, Service整体的生命时间是从onCreate()被调用开始,到onDestroy()方法返回为止。和Activity一样,Service在onCreate()中进行它的初始化工作,在onDestroy()中释放残留的资源。onCreate() 和 onDestroy()会被所有的Service调用,不论Service是通过startService()还是bindService()建立。
Service主要活动的方法是从onStartCommand() 或onBind()被调用开始,它们各自处理由startService()或 bindService()方法传过来的Intent对象。
如果Service是通过startService()开启的,那么它的活动生命周期和整个生命周期一同结束。
如果Service是通过bindService ()开启的,它们它的活动生命周期是在onUnbind()方法返回后结束。
注意:尽管一个被开启的Service是通过调用 stopSelf() 或 stopService()来停止的,没有一个对应的回调函数与之对应,即没有onStop()回调方法。所以,当调用了停止的方法,除非这个Service和客户组件绑定,否则系统将会直接销毁它,onDestory()方法会被调用,并且是这个时候唯一会被调用的回调方法。
Service使用注意事项
其实没有太多注意的,但是2中使用方式的开始和结束的方法是一对的,start和stop,bind和unbind,记住这个就好了,用一个成语表示就是:有始有终。