Android四大组件之服务

Android四大组件一,相当于一个看不见的Acticity,虽然多线程也是看不见的,也是在后台默默运行的,但是服务server和多线程Thread完全不一样!!!servere还是运行在主线程中,所以在service不要运行耗时的操作,会直接报错!

所以,先总结一下service的特点,然后再来挨着验证:
1、运行在主线程,不宜进行耗时操作;
2、相当于一个隐形的Activity;
3、运行的即使是运行的进程死掉,服务也不一定会死掉;

接下来看一下如何使用

1、构建服务 service

类似与四大组件的通用创建方式。直接新建,选择service,然后Exported表示其他App也可以访问这个服务,然后Enable表示开启这个服务,即可。AS会自动在xml中创建标签。

新的service要求重写onBind()函数,用户返回连接的Bind,后面会用到。

我们一般会手动重写一下onCreate(),onStartCommand(),onDestory()这三个函数。用于处理service需要做的事情。

2、启动服务 service

在Activity中,我们有两种方法启动service。
一种是直接启动,然后就不管了(当然也管不了),任由服务自身自灭,就算是服务完成了工作,Activity也不知道,完全互补干涩。相当于散养。
一种是在启动的时候,保留一个连接,通过这个连接可以随时监控service的状态,以及控制service。(圈养)

(1)散养(startService)

在Activity中,使用:
//开启
Intent i = new Intent(this,MyService.class);
startService(i);
//关闭
Intent i = new Intent(this,MyService.class);
stopService(i);

就像启动一个最简单的Activity,但是这种方法只能单纯的启动一个service,service启动之后就会自动干活,做完没有,以及什么时候做完的,Activity都是不知道。在调用stopService就会停止该服务。但我发现这样启动service之后,就算你直接将App finish之后,service还是没有Destory。

(2)圈养(bindService)

在Myservice中,写一个内部类,继承Binder,里面的方法自己写,暴露给Activity,用于控制service。然后申明一个MyBind的变量,在onBind函数中,将其返回出去。
在Activity中,深明一个ServiceConnection(),重写两个内部的方法,分别是连接成功时,和断开连接时调用,在onServiceConnection中,获取MyBinder对象。然后使用bindService(intent,ServiceConnection,…),进行绑定开启服务。这种方式可以多个Activity控制同一个Sevice,当最后一个与Service连接的Activity断开的时候,Service才会销毁。

测试

在明白了如何开启我们的服务之后,我们再来关心一下service的生命周期,以及service与Activity的联系。

问题:

1.如果同时使用了startService和bindService,怎样才能停止才服务?
2.两个Activity同时绑定了一个Service,当在一个Activity中使用了unbingService,服务会停止吗?
3.怎样使一个活动(进程)已经死亡了之后,保证服务会不停止,继续运行?

新建工程。工程目录结构如下
目录结构
我们一共需要两个Activity和一个service。

service文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MyService extends Service {
private static final String TAG = "MyService";
private MyBinder mybinder;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return mybinder;
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate: " );
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy: " );
}
class MyBinder extends Binder{
public void func1(){
Log.e(TAG, "func1: ");
}
public void func2(){
Log.e(TAG, "func2: " );
}
}
}

重写了onCreate,onStartCommand,onDestroy,onBind方法。新建了一个MyBinder内部类,用于绑定后,对Service的操作。

Activity1的布局文件以及java文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/startService"
android:text="startService"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/stopService"
android:text="stopService"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/bindService"
android:text="bindService"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/unbindService"
android:text="unbindService"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/changeActivity"
android:text="changeActivity"/>
</LinearLayout>

java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class MainActivity extends AppCompatActivity {
private MyService.MyBinder binder ;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startButton = (Button) findViewById(R.id.startService);
Button stopButton = (Button) findViewById(R.id.stopService);
Button bindButton = (Button) findViewById(R.id.bindService);
final Button unbindButton = (Button) findViewById(R.id.unbindService);
Button changeActivity = (Button) findViewById(R.id.changeActivity);
final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected: " );
binder = (MyService.MyBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
binder.func1();
binder.func2();
Log.e(TAG, "onServiceDisconnected: " );
}
};
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MyService.class);
startService(intent);
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MyService.class);
stopService(intent);
}
});
bindButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MyService.class);
bindService(intent,connection, Context.BIND_AUTO_CREATE);
}
});
unbindButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
unbindService(connection);
}
});
changeActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,MainActivity2.class);
startActivity(intent);
}
});
}
@Override
protected void onDestroy() {
Log.e(TAG, "onDestroy: " );
super.onDestroy();
}
}

Activity2的布局文件以及java文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/M2_bindService"
android:text="M2_bindService"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/M2_unbindService"
android:text="M2_unbindService"/>
</LinearLayout>

java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MainActivity2 extends AppCompatActivity {
private static final String TAG = "MainActivity2";
MyService.MyBinder binder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
final Button bind = (Button) findViewById(R.id.M2_bindService);
final Button unbind = (Button) findViewById(R.id.M2_unbindService);
final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected: " );
binder = (MyService.MyBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected: " );
}
};
bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity2.this,MyService.class);
bindService(intent,connection,BIND_AUTO_CREATE);
}
});
unbind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
unbindService(connection);
}
});
}
}

button顺序1 button顺序2

测试1:同时使用startService和bindService
点击顺序:1324和1342
输出结果:

1
2
3
E/MyService: onCreate:
E/MyService: onStartCommand:
E/MyService: onDestroy:

结论:如果同时使用startService和bindService,则需要同时使用stopService和unbindService才能结束掉服务。

测试2:两个Activity同时绑定了一个Service
点击顺序:356784
输出结果:

1
2
MyService: onCreate:
MyService: onDestroy:

结论:当两个Activity同时绑定了一个Service时,一个断开,只要还有一个Activity还与Service相连,那么就不会Service就不会死掉。
有趣的是,如果我们点击顺序为:3568 和38
输出结果:

1
2
3
4
E/MyService: onCreate:
E/MainActivity: onDestroy:
E/ActivityThread: Error....
E/MyService: onDestroy:

那么程度会报错,而且程序中,Activity的Destroy在服务的Destroy之前就已经结束了,导致了报错。

测试3:怎样使一个活动(进程)已经死亡了之后,保证服务会不停止
点击顺序:18 然后重新开启该应用, 2
输出结果:

1
2
3
4
E/MyService: onCreate:
E/MyService: onStartCommand:
E/MainActivity: onDestroy:
E/MyService: onDestroy:

可以看到,在程序已经onDestroy了之后,服务并没有断掉,所以说,使用startService的方式启动的服务,已经与本Activity无关了。在Activity已经死掉的情况之下,还是能继续运行。

如果文章对您有用请随意打赏,谢谢支持!