您的位置:首页 > 移动开发 > Android开发

写给初学者18_android_四大组件_Service

2017-04-19 17:15 387 查看

安卓18_四大组件-Service

如果说Activity是花枝招展的门面担当,那么Service就是辛勤的后台人员,并且Service是没有可视化界面的。需要注意的是Service也是组件,所以也是运行在主线程当中的,也就意味着不能执行耗时操作,虽然是运行在后台。如果要进行耗时操作,那么需要开启线程。

系统在内存紧张的时候会杀死一些优先级比较低的Activity,不过Service的默认优先级是高于Activity的。这样Service被杀死的几率就会比较小,并且有的Service杀死以后还可以再启动起来。

简单的举个例子,如果我使用Activity去播放音乐那么,当Activity不可见以后,却正在播放音乐怎么办,倘若系统一个需要内存,杀死当前的Activity怎么办,这样做的话,那安卓是真的没可能好用的。使用Service来进行音乐的播放,我们也就不会担心Activity的可见与否,以为它完全在后台运行。只不过要注意的是两者之间的通信。

官方定义

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。

主要能完成的事情

例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

Service的类型

本地服务 Local Service

范围:单个应用程序内部

案例:基本的一些耗时操作,比如下载。

远程服务 Remote Sercie

范围:几个应用程序之间,但是不能跨手机。

案例:比如有一个应用已经用服务的方式去做了多天气的获取,那么其他的应用就可以不用在开启这样的事情,直接去调用就好了。

Service的启动方式

start启动方式 非绑定式

特点:启动服务以后,和启动源不会有任何的关系,启动源无法获取到服务对象、

代码实现

1:写一个类继承自Service,Service是一个抽象类,当中有一个onBind需要我们实现,但是我们start的启动方式是可以不管这个方法的。

public class DemoService extends Service {

@Override
public void onCreate() {
super.onCreate();
Log.i("Service-life", "onCreate()");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Service-life", "onStartCommand()");
return super.onStart
bb8a
Command(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i("Service-life", "onDestroy()");
}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i("Service-life", "onBind()");
throw new UnsupportedOperationException("Not yet implemented");
}
}


2.在相应的组件中开启Service,开启服务是通过意图Intent,这里和Activity的启动是非常相似的,只不过叫startService();

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button btnStart;
private Button btnStop;
private Intent intent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
intent = new Intent(this, DemoService.class);
}

private void initView() {
btnStart = (Button) findViewById(R.id.btnStart);
btnStop = (Button) findViewById(R.id.btnStop);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
// 开启
startService(intent);
break;
case R.id.btnStop:
// 停止
stopService(intent);
break;
}
}
}


3.根据代码简单测试一下,这里在Service当中,我们将生命周期中回掉的方法都实现了一下。并且使用按钮来简单测试一下。



简单总结:

1.整个过程中,只有调用停止以后service对象才会销毁。

2.没有销毁的情况下,service是可以重启的。

3.onBind在这种启动模式下,并未回调到。

也可以很好的理解Service的生命周期图



注意

很显然这种启动方式是左边的这幅生命周期。但是明显可以感受到,服务启动以后,在运行的整个过程中,我们都无法获得Service对象,并且对其控制。

bind启动方式

特点:通过Ibinder接口实例,返回一个ServiceConnection对象,通过该对象的相关方法可以得到Service的对象,从而进行控制。

最基本的代码实现:

Service类

public class BindDemoService extends Service {

@Override
public void onCreate() {
super.onCreate();
Log.i("Service-life", "onCreate()");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Service-life", "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i("Service-life", "onDestroy()");
}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i("Service-life", "onBind()");
return null;
}

@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.i("Service-life", "unbindService()");
}
}


主要看的是onBind和upbindService

Activity中

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button btnStart;
private Button btnStop;
private Intent intentStart,intentBind;
private Button btnBind;
private Button btnUnbind;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
intentStart = new Intent(this, DemoService.class);
intentBind = new Intent(this,BindDemoService.class);
}

private void initView() {
btnStart = (Button) findViewById(R.id.btnStart);
btnStop = (Button) findViewById(R.id.btnStop);
btnBind = (Button) findViewById(R.id.btnBind);
btnUnbind = (Button) findViewById(R.id.btnUnbind);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
btnBind.setOnClickListener(this);
btnUnbind.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
// 开启
startService(intentStart);
break;
case R.id.btnStop:
// 停止
stopService(intentStart);
break;
case R.id.btnBind:
//绑定
bindService(intentBind,null, Service.BIND_AUTO_CREATE);
break;
case R.id.btnUnbind:
//解绑
unbindService(null);
break;
}
}

@Override
protected void onDestroy() {
super.onDestroy();

}
}


这对bindService的最后一个参数做一个说明:

1).Context.BIND_AUTO_CREATE

说明:表示收到绑定请求的时候,如果服务尚未创建,则即刻创建,在系统内存不足需要先摧毁优先级组件来释放内存,且只有驻留该服务的进程成为被摧毁对象时,服务才被摧毁

2).Context.BIND_DEBUG_UNBIND

说明:通常用于调试场景中判断绑定的服务是否正确,但容易引起内存泄漏,因此非调试目的的时候不建议使用

3).Context.BIND_NOT_FOREGROUND

说明:表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行,该标志位位于Froyo中引入。

结果



注意

可以看到onBind()方法被回调,当然我们在这里对第二个参数采用了空处理,第三个参数下面再来解释,但是可以发现Service和我们的Activity已经形成了绑定,当我绑定开启了一个服务以后,退出Activity时并没有解绑,就会出现途中的错误。同样道理,我如若没有绑定一个服务就开始解绑,或者解绑多次,同样也是会出错的。

通过ServiceConnection进行创建,并且获取到Service对象

Service类中

public class BindDemoService extends Service {

private MyBinder myBinder = new MyBinder();

@Override
public void onCreate() {
super.onCreate();
Log.i("Service-life", "onCreate()");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Service-life", "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();
Log.i("Service-life", "onDestroy()");
}
public  class MyBinder extends Binder{

// 定义相关方法
/*
一个返回当前Service对象的方法
*/
public BindDemoService getServie(){
return  BindDemoService.this;// 内部类访问外部类的对象
}

}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.i("Service-life", "onBind()");
return myBinder;
}

@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.i("Service-life", "unbindService()");
}

public void play(){
Log.i("Service-life", "play()-播放");
}
public void stop(){
Log.i("Service-life", "stop()-停止");
}public void next(){
Log.i("Service-life", "next()-下一首");
}
public void previous(){
Log.i("Service-life", "previous()-上一首");
}

}


注意

这里需要实现Binder并且在Binder当中我们可以做不少的事情,比如返回当前的Service对象。

Activity中:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button btnStart;
private Button btnStop;
private Intent intentStart, intentBind;
private Button btnBind;
private Button btnUnbind;
private BindDemoService bindDemoService;
// ServiceConnection对象
private ServiceConnection connection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
// Service连接时回调binder就是我们在onBind当中返回的binder
BindDemoService.MyBinder myBinder = (BindDemoService.MyBinder) binder;
bindDemoService = myBinder.getServie();
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};
private Button btnPlay;
private Button btnStopPlay;
private Button btnNext;
private Button btnPrevious;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
intentStart = new Intent(this, DemoService.class);
intentBind = new Intent(this, BindDemoService.class);
}

private void initView() {
btnStart = (Button) findViewById(R.id.btnStart);
btnStop = (Button) findViewById(R.id.btnStop);
btnBind = (Button) findViewById(R.id.btnBind);
btnUnbind = (Button) findViewById(R.id.btnUnbind);
btnPlay = (Button) findViewById(R.id.btnPlay);
btnStopPlay = (Button) findViewById(R.id.btnStopPlay);
btnNext = (Button) findViewById(R.id.btnNext);
btnPrevious = (Button) findViewById(R.id.btnPrevious);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
btnBind.setOnClickListener(this);
btnUnbind.setOnClickListener(this);
btnPlay.setOnClickListener(this);
btnStopPlay.setOnClickListener(this);
btnNext.setOnClickListener(this);
btnPrevious.setOnClickListener(this);

}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
// 开启
startService(intentStart);
break;
case R.id.btnStop:
// 停止
stopService(intentStart);
break;
case R.id.btnBind:
bindService(intentBind, connection, Service.BIND_AUTO_CREATE);
break;
case R.id.btnUnbind:
unbindService(connection);
break;
case R.id.btnPlay:
bindDemoService.play();
break;
case R.id.btnStopPlay:
bindDemoService.stop();
break;
case R.id.btnNext:
bindDemoService.next();
break;
case R.id.btnPrevious:
bindDemoService.previous();
break;
}
}

@Override
protected void onDestroy() {
super.onDestroy();

}
}


注意一下Service对象的获取方式



这里只是一个简单的模拟,当然对于Service初学者没有必要掌握的这么深,也不必要非要搞清楚Binder这个类到底是如何在做通信,基本的使用会了再去做深入的研究

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: