Service是android开发的四大组价之一。用来在后台(这个后台并不是后台线程,service也是在主线程中执行的)进行数据的操作。最常见的应用:push,音乐播放器,某些操作的监控(软件是否在运行,也就是常说的心跳)。
Service分为两种启动方式startService和bind。
顾名思义
start启动方式,启动以后就很少和外界进行交流了。终止service,service类的外部使用stopService,service自身使用stopself。
Bind方式,和android的组件进行绑定然后service就可以和组件间进行通信了。当组件销毁的时候service就会自动解绑并销毁。多个组件可以绑定同一个service,只有在所有的组件都销毁后service才会销毁。
Service的生命周期图
今天先对通过startService进行启动的service进行讲解。
大家可以通过和我一起写代码加深对Service生命周期的理解。
1、新建service
我们自己的service要继承于android.app.Service
public class TestService extends Service {
@Override
public IBinder onBind(Intent intent) {
Log.e("TestService", "onBind");
return null;
}
@Override
public void onCreate() {
Log.e("TestService", "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TestService", "onStartCommand");
Bundle bundle = null;
if(intent != null){
bundle = intent.getExtras();
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e("TestService", "onDestroy");
super.onDestroy();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
Log.e("TestService", "onConfigurationChanged");
super.onConfigurationChanged(newConfig);
}
@Override
public void onRebind(Intent intent) {
Log.e("TestService", "onRebind");
super.onRebind(intent);
}
@Override
public boolean onUnbind(Intent intent) {
Log.e("TestService", "onUnbind");
return super.onUnbind(intent);
}
}
2、我们先新建一个activity里面放置两个按钮,用来进行开启service和关闭service。代码如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/catalog_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/catalog_activity_top_bg_white"
android:clickable="true"
android:orientation="vertical">
<Button
android:id="@+id/start_service"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:onClick="testStartService"
android:text="startService"
/>
<Button
android:id="@+id/stop_service"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:onClick="testStopService"
android:text="stopService"
/>
</LinearLayout>
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_layout);
}
public void testStartService(View view){
Log.e("TestService", "testStartService");
Intent intent = new Intent();
intent.setClass(this, TestService.class);
startService(intent);
}
public void testStopService(View view){
Log.e("TestService", "testStopService");
Intent intent = new Intent();
intent.setClass(this, TestService.class);
stopService(intent);
}
}
以下是运行效果图
以下是对service生命周期的解释
1当点击startService的时候我们看控制台的log输出
07-26 09:13:19.283 3078-3078/? E/TestService: testStartService
07-26 09:13:19.307 3078-3078/? E/TestService: onCreate
07-26 09:13:19.307 3078-3078/? E/TestService: onStartCommand
可知启动service先执行onCreate,再执行onStartCommand。请再看一遍service的生命周期。
2当再次点击startService的时候,log如下
07-26 09:20:36.583 3078-3078/? E/TestService: testStartService
07-26 09:20:36.608 3078-3078/? E/TestService: onStartCommand
通过上面的log发现当service正在运行的时候,再次调用startService并没有调用onCraete方法,那么这也就告诉我们启动了service以后,如果想给service传递东西那么service必须在onStartCommand中进行处理。在平时项目中也都是这么做的,我的习惯是onCreate直接 @Override
public void onCreate() {
Log.e("TestService", "onCreate");
super.onCreate();
}
里面什么操作也不写。
3终止service,我们点击testStopService发现
07-26 09:24:29.653 3078-3078/? E/TestService: testStopService
07-26 09:24:29.676 3078-3078/? E/TestService: onDestroy
比如我们启动了service,service处理完了相应的任务,那么我们就可以直接在service当中调用stopSelf()终止service。
我们在做项目当中经常会遇到这样的情况,service要一直在后台运行,如果由于某些原因service意外终止了,也能够自动启动。Push常常就是这样的要求。
1、新建一个BroadcastReceiver
public class TestBroadcaseReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent();
intent.setClass(context, TestService.class);
context.startService(intent1);
}
}
在manifest中进行注册
<receiver
android:name="com.yuanxzh.service.TestBroadcaseReceiver">
<intent-filter android:priority="0x7fffffff">
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
通过上面的操作当service意外终止的时候,我们通过一些系统广播就可以将已经关闭的service重新启动。
在这里一定要注意service虽然看不见但是是在主线程中,所以我们一定不能在service当中进行耗时的操作。