Service 作为Android的四大组件之一,如果没听过Service,怎么能说能说自己是一个Android开发者呢,实际上,Service 在Android程序中扮演者不可或缺的角色,很多应用在从服务器获取数据、进行后台工作(播放音乐)是都是使用的 Serive 来完成,服务就相当于一个没有UI界面的Activity,作为Android的四大组件之一,我们先看一下服务的生命周期:
通过这张图,我们可以清楚的看到,服务的启动有两种方式,一种是通过调用 startService 方法,另一种是调用 bindService 方法,服务的结束可以由系统结束或者由我们调用方法来结束,根据服务的两个启动方法,我们也有两个对应的结束服务的方法 : stopService 方法和 unBindService 方法,下面我们用一个简单的例子来进一步理解服务的生命周期问题:
新建一个Android工程:
activity_main.xm:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
tools:context="com.example.administrator.blogservice.MainActivity">
<Button
android:id="@+id/startServiceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开启服务" />
<Button
android:id="@+id/stopServiceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭服务"/>
</LinearLayout>
布局中两个按钮分别用于启动服务和关闭服务,Ok,那么我们既然要用到服务,那么自然我们要在 AndroidManifest.xml 文件中注册它了。我们新建一个类MyService,继承于Service类,并且在AndroidManifest.xml 文件中注册这个服务, 下面是MyService.java:
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
/**
* Created by Administrator on 2017/3/2.
*/
public class MyService extends Service {
private String TAG = "MyService";
/*
* 服务被创建的时候会调用这个方法
*/
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
}
/*
* 服务被创建之后,这个方法会被立即调用,如果我们需要服务一经创建就执行某些功能,
* 我们可以把要执行的功能的逻辑代码写在这个方法里面
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/*
* 这个方法当服务被绑定的时候会调用,这里我们先不用管
*/
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return new MyTask();
}
/*
* 这个方法当服务被结束的时候(被系统杀死或者被主动结束)调用
*/
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
}
private class MyTask extends Binder { // 自定义的内部类来完成对应功能
}
}
在这个类中我们重写了父类Service类中的几个方法。并且在对应的方法中都打上了 Tag,这里我们注意到MyService 类中必须重写的一个方法是 onBind 方法,这个方法会在当前服务对象和 Activity 对象绑定的时候调用,但是在这里它不是主角,我们接下来先看看MainActivity.java:
import android.content.Intent;
import android.net.sip.SipAudioCall;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button button = null;
private Intent intent = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.startServiceButton);
button.setOnClickListener(listener);
button = (Button) findViewById(R.id.stopServiceButton);
button.setOnClickListener(listener);
}
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.startServiceButton:
intent = new Intent(MainActivity.this, MyService.class);
/*
* 这里调用了 startService 方法来启动一个服务,服务一旦启动,必须主动关闭,
* 否则的话只要当前进程一直在运行,服务就会一直处于执行状态,
* 所以当我们不需要使用服务的时候,我们应该及时停止服务,节省资源
*/
startService(intent);
break;
case R.id.stopServiceButton:
if(intent == null) {
intent = new Intent(MainActivity.this, MyService.class);
}
/*
* 调用 stopService 方法来停止一个服务,这个方法对应于 startService 方法启动的服务,
* 参数也是一个 Intent 对象
*/
stopService(intent);
break;
}
}
};
}
在主函数中,我们对两个按钮进行了单击事件监听,监听事件分别对应于开始服务和停止服务,好了,让我们来看看效果:
我们把LogCat中的信息清除,单击“开启服务”按钮:
我们看到,MyService 类中的 onCreate 方法和 onStartCommand 方法分别调用了一次。证明 onStartCommand 方法在服务创建之后就会立即被调用,我们再点击“开启服务”按钮试试:
我们可以看到,即使我们单击了两次“开启服务”按钮, MyService 中的 onCreate 方法仍然没有被调用。只是调用了 onStartCommand 方法,因为同一个服务只能存在一个实例,因此,当一个服务已经被创建的时候,再去创建这个服务只会调用这个服务的 onStartCommand 方法。接下来我们点击“关闭服务”按钮来结束服务:
OK, 服务成功的被销毁。
这里的服务,我们仔细思考后可以发现,当这个服务启动之后,我们是无法对其进行具体的操作的,什么意思呢,就是我们启动了这个服务之后,这个服务就去做自己的事情了,我们无法知道服务在做什么事情,或者是做的事情的进度是多少了,我们只能启动和结束这个服务,从某些方面来说,这显然是不合理的。那么怎么解决呢,还记得MyService 类中的 onBind 方法吗,我们之前说过,这个方法当当前服务和 Activity 绑定的时候会调用。OK,下面让我们来看看怎么通过这个方法来实现 Activity 和服务的绑定, 修改相关代码:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
tools:context="com.example.administrator.blogservice.MainActivity">
<Button
android:id="@+id/startServiceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开启服务" />
<Button
android:id="@+id/stopServiceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭服务"/>
<Button
android:id="@+id/bindServiceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="绑定服务"/>
<Button
android:id="@+id/unBindServiceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="解绑服务"/>
</LinearLayout>
在 activity_main.xml 布局文件中,我们增加了两个按钮用于绑定服务和解绑服务,接下来我们来看一下 MyService 类:
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
/**
* Created by Administrator on 2017/3/2.
*/
public class MyService extends Service {
private String TAG = "MyService";
/*
* 服务被创建的时候会调用这个方法
*/
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
}
/*
* 服务被创建之后,这个方法会被立即调用,如果我们需要服务一经创建就执行某些功能,
* 我们可以把要执行的功能的逻辑代码写在这个方法里面
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
/*
* 这个方法是当服务和 Activity 绑定的时候会调用的方法,返回的是一个 IBinder 对象,
* 一般我们会新建一个内部类继承于 Binder 类,一般我们会把要执行的逻辑放在这个
* 当 onBinder 方法被调用的时候,我们就可以返回这个类的实例化对象,
* 这里说一下 Binder 类实现了 IBinder 接口,因此 Binder 类的对象同时也是 IBinder 对象
* 那么绑定这个 Service 的 Activity 就可以得到这个内部类的实例的引用
* 之后我们可以在Activity 中可以通过得到的这个内部类的引用来获取我们正在做的事情的信息,
* 并且可以通过这个内部类提供的方法加以控制,这样就实现了 Service 和绑定的 Activity 之间的通信
*/
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return new MyTask();
}
/*
* 这个方法当服务被结束的时候(被系统杀死或者被主动结束)调用
*/
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
}
/*
* 这里我们新建了一个内部类,我们把我们想做的事情写在这个内部类中,
* 并且一般我们会实现一些公用方法用于让绑定这个 Service 的 Activity 可以控制我们要做的事情
*/
public class MyTask extends Binder { // 自定义的内部类来完成对应功能
}
}
那么在这里 onBind 方法就是主角了。简单来说,这个方法在 Activity 和 Service 绑定的时候被调用,并且返回一个 IBinder 对象给 Activity, 之后 Activity 就可以通过这 IBinder 对象进行和绑定的服务之间的通信。最后我们来看一下 MainActivity.java:
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button button = null;
private Intent intent = null;
private MyService.MyTask myBind = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.startServiceButton);
button.setOnClickListener(listener);
button = (Button) findViewById(R.id.stopServiceButton);
button.setOnClickListener(listener);
button = (Button) findViewById(R.id.bindServiceButton);
button.setOnClickListener(listener);
button = (Button) findViewById(R.id.unBindServiceButton);
button.setOnClickListener(listener);
}
/*
* 新建一个 ServiceConnection 匿名类对象并且重写里面的抽象方法,
* 用于当前 Activity 绑定服务和解绑服务调用
*/
private ServiceConnection connection = new ServiceConnection() {
// 这个方法会在 Activity 绑定服务成功的时候调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBind = (MyService.MyTask) service; // 获取 MyService 中 onBind 方法返回的 IBinder 对象
Toast.makeText(MainActivity.this, "绑定服务" ,Toast.LENGTH_SHORT).show();
}
/*
* 这个方法在服务被异常结束(被系统回收)的时候调用,
* 当服务于 Activity 正常解绑的时候,这个方法是不会被调用的
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.startServiceButton:
intent = new Intent(MainActivity.this, MyService.class);
/*
* 这里调用了 startService 方法来启动一个服务,服务一旦启动,必须主动关闭,
* 否则的话只要当前进程一直在运行,服务就会一直处于执行状态,
* 所以当我们不需要使用服务的时候,我们应该及时停止服务,节省资源
*/
startService(intent);
break;
case R.id.stopServiceButton:
if(intent == null) {
intent = new Intent(MainActivity.this, MyService.class);
}
/*
* 调用 stopService 方法来停止一个服务,这个方法对应于 startService 方法启动的服务,
* 参数也是一个 Intent 对象
*/
stopService(intent);
break;
case R.id.bindServiceButton:
onBindServie();
break;
case R.id.unBindServiceButton:
onUnBindService();
break;
}
}
};
/*
* 绑定服务的方法
*/
private void onBindServie() {
if(intent == null) {
intent = new Intent(this, MyService.class);
} else {
intent.setClass(this, MyService.class);
}
// 调用bindService 方法,并且通过 Intent 对象绑定服务,第三个参数代表服务绑定成功的时候自动创建绑定成功的服务对象
bindService(intent, connection, BIND_AUTO_CREATE);
}
/*
* 解绑服务的方法
*/
private void onUnBindService() {
// 通过 unBinderService 方法来解绑服务,这个方法和 bindService 方法对应
unbindService(connection);
}
}
在 MainActivity 中我们新建了一个 ServiceConnection 匿名类对象,这个对象中的 onServiceConnected 方法在服务和当前 Activity 绑定成功的时候会被调用。最后,让我们来运行一下:
Nice,成功的显示出了绑定服务的 Toast 提示信息,并且LogCat 中的显示也证明 MyService 类中的 onBind 方法确实调用了。那么下面我们单击“解绑服务”按钮:
服务成功的被摧毁!
那么这里还有一个问题:如果同时调用了 startService 方法和 bindService 方法之后要怎么结束这个服务呢?我们还是通过实验来看:
我们可以看到,当我们同时点击了 “开启服务”按钮和“绑定服务”按钮的时候,我们必须要同时点击 “关闭服务”按钮和“解绑服务”按钮才能将服务摧毁,这样是因为这个服务被创建了两次吗,其实并不是,如果这个服务被创建了两次,那么应该打印两次 onCreate Log 信息,但是并没有。这里我们可以理解成开启服务的两个方法(startService、bindService)之间并不互通,一个开启方法对应一个结束方法,只有两个开启的方法对应的结束方法都被调用了才可以结束这个服务。
关于服务的用法这里介绍的只是入门级别的,要想对服务理解更深,日后还得多加学习。
如果博客中有什么不正确的地方,还请多多指点。
谢谢观看。。。
1617

被折叠的 条评论
为什么被折叠?



