Service就是去掉界面的Activity
Service与Activity较为相似,都可代表可执行的程序,都有生命周期。区别是Service工作在后台,Activity工作在前台。其实根据功能来选择是使用Activity还是Service:需要用户交互(UI)就使用Activity,不需要用户交互,只需做一些处理工作,就用Service。
Service可以做些什么
他要做的就是Activity不需要界面的操作,比如闹钟服务,定了时间后我们不再需要界面显示但是需要计时系统运行。又比如我们短信某些APP比较人性化,发送了短信验证码后会有个自动读取短信验证码的功能,也可以用一个后台Service来监控,Service是一个后台默默无闻的工作者。
Service一种是启动状态,主要用于后台计算。另一种是绑定状态,主要用于其他组件和service的交互。
Service的这两种状态可以共存。
Service的配置
与Activity相似,创建Service需要继承Service类和实现AndroidManifest.xml文件注册。
public class MyService extends Service {
//onBind(Intent intent)方法必须实现。
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return binder;
}
}
AndroidManifest.xml中声明此Service(Android Studio自动就添加了声明)
<service android:name=".MyService"/>
//与Activity类似也可添加Intent-filter匹配过滤规则,说明该Service可被那些Intent启动
Service运行和停止
启动Service有两种方式:
- 两者不访问,调用Context的startService(Intent)启动,调用stopService(Intent)来停止。
- 两者互通数据,则应使用bindService(Intent service,ServiceConnection coon,int flags)绑定和unbindService()解注册。
方式一,两者不访问
我们注册好的这个Service只是一个框架,还需要进一步操作,才能让他跑起来。
设计代码,让按钮点击Service 跑起来,再次点击Stop。代码如下:
在MainActivity.java中用Intent启动Service:
public class MainActivity extends AppCompatActivity {
private Button open,close;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
open = (Button) findViewById(R.id.button);
close = (Button) findViewById(R.id.button1);
final Intent intent = new Intent(this,MyService.class);
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//启动Service
startService(intent);
}
});
close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//关闭Service
stopService(intent);
}
});
}
}
Myservice.java
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
Log.v("test","onBind");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.v("test","onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("test","onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("test","onDestroy");
}
}
点击打开Service:
04-24 12:50:37.176 3448-3448/com.alphathink.myactivity V/test: onCreate
04-24 12:50:37.177 3448-3448/com.alphathink.myactivity V/test: onStartCommand
点击关闭Service:
04-24 12:51:51.416 3448-3448/com.alphathink.myactivity V/test: onDestroy
多次点击打开Service:
04-24 12:58:14.032 10286-10286/com.alphathink.myactivity V/test: onCreate
04-24 12:58:14.033 10286-10286/com.alphathink.myactivity V/test: onStartCommand
04-24 12:58:16.794 10286-10286/com.alphathink.myactivity V/test: onStartCommand
04-24 12:58:17.480 10286-10286/com.alphathink.myactivity V/test: onStartCommand
可以发现,onCreate()方法不再执行,但会执行onStartCommand()方法。
方式二,实现本地Service绑定和通信
绑定Service:bindService(Intent service,ServiceConnection coon,int flags)
解绑Service:unbindService(ServiceConnection coon)
参数含义:
- service:通过传入的intent携带service来指定绑定service对象
- coon:ServiceConnection对象,监听访问者与Service连接状况,连接状态则调用其下的onServiceConnected(ComponentName name,IBinder service),异常终止连接则调用onServiceDisconnected(ComponenttName name)方法,主动解注册则不调用。
- flags:绑定时确定是否在无Service下新建Service,0–不创建,BIND_AUTO_CREATE–自动创建。
我们实现Service的时候,必须要实现如下方法:
@Override
public IBinder onBind(Intent intent) {
Log.v("test","onBind");
return binder;
}
在上边的coon连接状态下调用的onServiceConnected(ComponentName name,IBinder service)中也有个IBinder对象,没错两者关联,当我们创建Service时,onBind()方法返回的IBinder对象会在这个方法中复用。访问者就和Service建立起联系了。IBinder充当了桥接的角色。我们与Service通信就是通过IBinder对象来做信使的。实际开发也会有自定义IBinder对象来实现自己的业务逻辑。
MyService.java
public class MyService extends Service {
private int count;
private boolean quit;
private MyBinder binder = new MyBinder();
public class MyBinder extends Binder {
public int getCount(){
return count;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.v("test","onBind");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.v("test","onCreate");
new Thread(){
@Override
public void run() {
while(!quit){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("test","onDestroy");
this.quit = true;
}
@Override
public boolean onUnbind(Intent intent) {
Log.v("test","onUnbind");
return super.onUnbind(intent);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button open,close,status;
private MyService.MyBinder binder;
private ServiceConnection coon = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v("test","service is connected");
binder = (MyService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v("test","service is disconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
open = (Button) findViewById(R.id.button);
close = (Button) findViewById(R.id.button1);
status = (Button) findViewById(R.id.button2);
final Intent intent = new Intent(this,MyService.class);
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//绑定Service
bindService(intent,coon, Service.BIND_AUTO_CREATE);
}
});
close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//解绑Service
unbindService(coon);
}
});
status.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"service目前count值为"+binder.getCount(),Toast.LENGTH_SHORT).show();
}
});
}
}
运行后,点击打开Service:
04-27 16:53:24.241 15006-15006/com.alphathink.myactivity V/test: onCreate
04-27 16:53:24.244 15006-15006/com.alphathink.myactivity V/test: onBind
04-27 16:53:24.245 15006-15006/com.alphathink.myactivity V/test: service is connected
点击关闭Service:
04-27 16:53:55.268 15006-15006/com.alphathink.myactivity V/test: onUnbind
04-27 16:53:55.269 15006-15006/com.alphathink.myactivity V/test: onDestroy
点击获取状态:
这样就完成了绑定service的使用,与方法一不同的是重复按打开service但是onBind()只会执行一次。
Service的生命周期:
分析了以上两种方式,当然Service的生命周期也会有两种:(分别对应方式一二)
Service中的ANR
普通Service局限性:
- 与启动Service的应用位于同个线程中。
- 非新线程,不能处理耗时任务。(Activity5s,Broadcast10s,Service20s(小概率)会出现ANR)
测试:在方式一中更改onStartCommand()方法为:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.v("test","onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
大约20s出现ANR。所以出现了IntentService。
IntentService的使用
IntentService是Service的子类,IntentService使用队列来管理请求Intent,然后开启新线程来处理他,保证同一时刻处理一个Intent。因此他不会阻塞主线程。避免了ANR的出现。另IntentService为onBind()和onStartCommand()提供了默认实现,因此我们不必重复实现。只需要实现onHandleIntent()方法即可。
MyIntentService.java
public class MyIntentService extends IntentService {
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button open;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
open = (Button) findViewById(R.id.button);
final Intent intent = new Intent(this, MyIntentService.class);
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//绑定Service
Log.v("test","ssssss");
startService(intent);
}
});
}
}
是不是简便清爽了很多呢。由于在新线程操作,测试20s耗时操作的时候是不会出现ANR的。