目录
一、Service简介
二、Service分类
1、Started Service
2、Bound Service
3、启动Service回调的方法
4、通过代码还原Service生命周期
三、使用IntentService
1、为什么使用IntentService ?
2、 IntentService服务为什么可以自动创建线程?为什么可以自动结束服务?
Service是Android的四大组件之一。
作用:
后台长期处理耗时的逻辑。
Service与Activity的区别:
不同点:Service与Activity功能大抵相同,区别在于Service不存在UI界面,Service在后台运行,不能与用户进行交互功能。
相同点:都需要在清单文件中注册,且都有生命周期。
Service的特点:
(1)、在后台运行,即使应用退出,也不会停止服务,只有在杀死APP进程时,才会停止服务。
(2)、Service运行在主线程中。所以,当我们执行一些耗时的操作时,可以在服务中创建子线程来处理耗时的操作。
(3)、Service应用广泛,例如:音乐播放,下载文件等。
更多关于Service的内容详见官方文档:服务概览 | Android 开发者 | Android Developers
对于Service服务我们都不陌生,它大概在我们手机中是这样的。
接下来开始学习如何使用Service服务吧。
按照启动方式可以分为:
当组件通过调用 startService() 方法启动 Service ,这时,Service处于启动状态,可以在后台无限期的运行,只有自身调用stopSelf() 方法 或者 其他组件调用 stopService() 方法才会停止Service。
当组件通过调用 bindService() 方法绑定 Service,这时,Service处于绑定状态,多个组件可以绑定在一个Service上,当绑定Service的所有组件解绑之后,该Service被销毁。
两种启动方式的生命周期如下:
startService():启动服务
(手动调用)不受调用组件的控制,可以在后台无限期的运行。
bindService():绑定服务
(手动调用)将多个组件与服务绑定在一块,随着组件的消亡而消亡。
onCreate():创建服务
(自动调用)无论是开启服务还是绑定服务,最开始的回调函数肯定是onCreate(),当第一次创建Service的时候调用该方法,多次调用startService()方法不会重复调用onCreate() 方法。适合做一些初始化操作。
onStartcommand():重复开始服务
(自动调用)当多次执行startService()方法的时候,onStartcommand()都会执行。
onBind():绑定服务
(自动调用)当一个组件想要通过bindService()
绑定service时,系统会回调该方法。该方法需要实现一个接口,通过返回IBinder对象实现用户通信。若不需要绑定service则返回null,否则必须实现。
unbindService():解绑服务【相对于某个组件来说】
(手动调用)当组件想要与该服务解绑时调用,只有在所有用户解绑之后才会调用onUnbind()回调函数。
onUnbind():解绑服务【相对于服务来说】
(自动调用)当所有捆绑服务的组件解绑之后,系统自动调用onUnbind()函数,将服务解绑。
onDestroy():销毁服务
(自动调用)当Service调用这个函数的时候,这个服务就销毁停止了。下次在用的时候只能执行onCreate()函数进行创建。
stopService():结束服务
(手动调用)其他组件通过调用该函数,将以startService()启动的Service停止掉。
stopSelf():结束服务
(手动调用)当前Service调用此方法来终结自己。
案例:在MainActivity中定义四个按钮,分别是:启动服务,绑定服务,解绑与结束服务。点击相应的按钮完成相应的功能。
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动服务"
android:id="@+id/start_button"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="绑定服务"
android:id="@+id/bind_button"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解除绑定"
android:id="@+id/unbind_button"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="结束服务"
android:id="@+id/stop_button"/>
<TextView
android:id="@+id/text"
android:text="XXXXXX"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:textSize="28sp"/>
</LinearLayout>
AndroidManifest.xml
注册服务:<service>
其中有两个属性:
1、android:enabled:表示指定的Service能否被实例化,true表示能,false表示不能。
2、android:exported:表示指定的其他组件能否调用Service或者与其交互,true表示能,false表示不能。当该值为false时,只有同应用的组件或者具有相同用户ID的程序才能启动或者绑定到Service 。
<!-- 注册服务 -->
<service android:name=".MyService"/>
MainActivity.java
package com.example.servicedemo1;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button start_button;
private Button bind_button;
private Button unbind_button;
private Button stop_button;
private TextView text;
private static final String TAG1 = "serviceConnection";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//代码重构
extracted();
//创建Intent对象,用于服务相关操作
Intent intent = new Intent(MainActivity.this, MyService.class);
//启动服务
startListener(intent);
//绑定服务
bindORunbindListener(intent);
//结束服务
stopListener(intent);
}
/**
* 代码重构,获取控件
*/
private void extracted() {
start_button = this.findViewById(R.id.start_button);
bind_button = this.findViewById(R.id.bind_button);
unbind_button = this.findViewById(R.id.unbind_button);
stop_button = this.findViewById(R.id.stop_button);
text = this.findViewById(R.id.text);
}
/**
* 点击启动服务按钮事件
* @param intent
*/
private void startListener(Intent intent) {
//点击“启动服务”的事件处理
start_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//startService():启动服务
startService(intent);
//将结果显示到页面
text.setText("我已经启动服务啦!");
}
});
}
/**
* 点击绑定与解绑服务的按钮事件
*
* @param intent
*/
private void bindORunbindListener(Intent intent) {
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG1,"调用onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG1,"调用onServiceDisconnected");
}
};
点击“绑定服务”的事件处理
bind_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//bindService():绑定服务
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
text.setText("我已经绑定服务啦!");
}
});
点击“解除绑定”的事件处理
unbind_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//unbindService():解绑服务
unbindService(serviceConnection);
text.setText("解除绑定服务啦!");
}
});
}
/**
* 结束服务按钮事件
*/
private void stopListener(Intent intent) {
//点击“结束服务”的事件处理
stop_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//stopService():结束服务
stopService(intent);
text.setText("服务已经结束啦!");
}
});
}
}
MyService.java
package com.example.servicedemo1;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "MyService";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "创建服务 ——> onCreate()");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "绑定服务 ——> onBind()");
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "重启服务(首次为启动) ——> onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "解绑服务 ——> onUnbind()");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "销毁服务 ——> onDestroy()");
}
}
结果:
(1)、第一次点击“启动服务”时:onCreate() ——> onStartCommand()
(2)、再次点击“启动服务”时:onStartCommand()
(3)、点击“启动服务”后又点击“绑定服务”时:onCreate() ——> onBind()
(4)、点击“解绑服务”时:onUnbind()
(5)、点击“结束服务”时:onDestroy()
如图:
由于Service不会专门启动一个线程执行一些耗时的操作,导致所有的操作都是在主线程中进行的,稍不留神就会造成ANR异常,所以需要手动来创建一个线程可供Service执行耗时操作。
另一个原因就是:Service启动后不会停止,只有在自身调用 stopSelf() 方法或者其他组件调用 stopService() 方法时才停止。
而IntentService很好的避免了这两个问题。
首先创建一个Service,让他继承IntentService类,然后在清单文件注册Service。
<service android:name=".MyIntentService"/>
public class MyIntentService extends IntentService {
}
然后在MainActivity.java 中启动MyIntentService
Intent intent1 = new Intent(MainActivity.this, MyIntentService.class);
startService(intent1);
最后编写MyIntentService代码,使他完成一个耗时操作。
package com.example.servicedemo1;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
/**
* intentService服务完成一个耗时操作
*/
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
}
//构造方法
public MyIntentService() {
super("MyIntentService");
}
//耗时任务
@Override
protected void onHandleIntent(@Nullable Intent intent) {
int i = 10;
Log.e(TAG,"IntentService服务启动");
Toast.makeText(this, "IntentService服务启动", Toast.LENGTH_SHORT).show();
while (i > 0) {
Log.i(TAG, i + "");
i--;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.e(TAG,"IntentService服务结束");
Toast.makeText(this, "IntentService服务结束", Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
}
}
效果如下:
当启动IntentService时,会自动开启一个Thread,进行耗时操作,当Thread运行结束之后,IntentService也会结束。
通过源码了解一下他的处理方式。
IntentService是一个抽象类,继承Service类,所以它是一种特殊的Service,因为它内部封装了handlerThread和handler的。
public abstract class IntentService extends Service
下面看onCreate()方法。
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); 创建了一个Handler线程,thread.start() 启动了这个线程。
thread.getLooper() 获取这个线程的Looper对象。
new ServiceHandler(mServiceLooper) 创建一个内部类ServiceHandler对象,将Looper对象传递给它。
下一步走到了 onStartCommand() 方法
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
这个方法里第一件事做的就是,调用onStart() 方法。
接下来看onStart() 方法
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
通过 mServiceHandler.sendMessage(msg) 将message发送到消息队列,消息处理又回到serviceHandler里面的handleMessage做。
紧接着回到内部类 ServiceHandler 中 执行 handleMessage() 方法。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
在这个方法中,调用了 onHandleIntent((Intent)msg.obj) 这个抽象方法,但它留给子类去实现。
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
最后调用 stopSelf(msg.arg1) 停止服务,给出的定义是立即停止,但是当有参数的时候,会等所有的任务都执行完,才停止服务。