Android日记之Service的基本使用
前言
上回小米面试问到Servic的时候懵了一下,因为基本很少用到,现在就再次来复习一下。
正文
Service的生命周期
Service的生命周期Service属于Android的四大组件之一,运行在主线程当中,适用场景在不需要跟用户交互而又需要长期运行的任务的时候可以用到Service。
Service的使用方法主要分为两种,
startService()
和bindService()
,两种的生命周期稍微不一样,这里着重说几点。
1.每调用一次startService()
就会调用一次onStartCommand()
生命周期,但是onCreate是只调用一次的。
2.Service通过BindService()
绑定后,将会一直运行下去,直到使用unBindService()
方法或者它的Activit被销毁才回结束。
3.如果方法已经被绑定了,在没有解绑的情况下,stopService()
是无法停止服务的,就算生命周期走到了onDestroy()
也无法停止。
4.如果一开始先调用startService()
方法后再去调用BindService()
后,需要同时StopService()
和unBIndService()
方法才能同时销毁。
如何使用Service
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
首先看代码,使用一个Service就是要继承这个类,然后必须重写onBind
这个方法,我们先暂时不看这个方法,那一些处理业务逻辑的方法要写在哪呢?这时我们就可以重写Service中其他的一些方法了。
public class MyService extends Service {
public MyService() {
}
//先不看这个方法
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@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();
}
}
这里又重写了三个方法,onStartCommand()
我们已经讲过了,每次启动一次Service就会调用一次这个方法,onCreate()
会在服务创建的时候调用,onDestroy()
就会在服务销毁的时候调用。
一般来说逻辑业务都是写在onStartCommand()
方法里的,需要销毁资源的时候就是在onDestroy()
里面。需要注意的是,每一个Service和Activity一样,都需要再AndroidManifest.xml进行注册才能使用。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
启动服务
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button b1, b2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1 = findViewById(R.id.button1);
b2 = findViewById(R.id.button2);
b1.setOnClickListener(this);
b2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);
break;
case R.id.button2:
Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent);
break;
default:
break;
}
}
}
创建两个button,一个启动服务一个停止服务,我们通过Intent来进行实现的。启动服务的时候服务会一直在运行状态,知道点击了停止服务的按钮服务才会停止下来,那有没有其他的办法不通过停止按钮来进行服务停止呢。这时候只要在Service的任何要停止的位置调用stopSelf()
就可以停止服务了。
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.d("ServiceDemo","onCreate:服务创建");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("ServiceDemo","onStartCommand:服务在执行");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("ServiceDemo","onDestroy:服务销毁");
}
}
依次点击启动按钮和停止按钮的生命周期如图
Activity和Service进行通信
我在这里写一个例子举例这两个怎么进行交互,因为通过刚才的学习,发现Activity只负责启动和停止Service后好像就没什么用的,这时候就用到我们刚才忽略的onBind()
方法了。
public class DownLoadBinder extends Binder {
public void startDownLoad(){
Log.d("","startDownLoad excuted");
}
public int getDonwload(){
Log.d("","getDonwload excuted");
return 0;
}
}
使用这个方法之前我们需要创建一个Binder对象一起配合实现功能,我们这里模拟一个下载功能,创建一个DownLoadBinder
来继承Binder来实现。
public class MyService extends Service {
private DownLoadBinder downLoadBinder = new DownLoadBinder();
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return downLoadBinder;
}
......
}
然后实例化这个类,直接在onBind()
方法里返回就好了,接下来在MainActivity修改。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button b1, b2, bind, unBind;
private DownLoadBinder downLoadBinder = new DownLoadBinder();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这两个是启动和开始服务按钮
b1 = findViewById(R.id.button1);
b2 = findViewById(R.id.button2);
//这两个是绑定和解绑服务按钮
bind = findViewById(R.id.bind);
unBind = findViewById(R.id.unBind);
b1.setOnClickListener(this);
b2.setOnClickListener(this);
bind.setOnClickListener(this);
unBind.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
break;
case R.id.button2:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
break;
case R.id.bind:
//绑定服务
Intent bindService = new Intent(this,MyService.class);
bindService(bindService,connection,BIND_AUTO_CREATE);
break;
case R.id.unBind:
unbindService(connection);
//解绑服务
break;
default:
break;
}
}
//创建ServiceConnect
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downLoadBinder = (DownLoadBinder) service;
downLoadBinder.startDownLoad();
downLoadBinder.getDonwload();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
这里首先创建一个ServiceConnection的匿名类,重写两个onServiceConnected()
和onServiceDisconnected()
这两个方法,然后通过绑定服务的时候调用,这时候我们就可以在Activity场景中调用DownloadBinder的方法了,在绑定的方法里面需要接受三个参数,第一就是刚刚构建的Intent对象,第二个就是创建出来的ServiceConnection实例,第三个是标志位,这里传入的BIND_AUTO_CREATE表示绑定后就会自动创建服务,这时候服务才会开始执行。MyService不仅能和这个Activity进行绑定,跟其它Activity进行绑定也是可以的。
InetntService
刚刚也说过Service是运行在主线程的,所以说如果运行一些很耗时的服务,就很容易造成ANR(Application not Responding),这个时候就需要多线程的帮助了,而这Intent就是为此而生的。我们可以把这个类看成是HandlerThread和Service的结合体。在这个类里开启一个子线程,然后做一些耗时的操作。它是一个异步的会自动停止的类。
public class MyIntentService extends IntentService {
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@androidx.annotation.Nullable @Nullable Intent intent) {
//具体逻辑
}
}
使用方法和Service差不多,耗时的操作写在onHandleIntent()
里,它首先要提供一个构造函数,然后调用父类的构造函数。IntentService也是可以启动多次的,每次也只会执行一个工作线程,然后执行完在执行下一个,依次进行下去。关于IntentService一些具体的使用注意,后面会写一章源码分析来进行讲解。
参考
- [郭霖] 第一行代码Android(第二版)