關於Service你所需要知道內容(一)
根據下面的目錄來介紹和理解Service中的知識點:
一.Service的兩種生命週期
service啟動有兩種方式:啟動服務startService,繫結服務bindService。有不同是生命週期,如下所示:
1.若一個Service被多次startService啟動,onCreate被呼叫一次,只有onStartCommand被呼叫多次。
2.onStartCommand必須放回一個整數=描述系統在殺死服務後應該如何繼續執行:
a.START_NOT_STICKY;不會重建服務,除非還存在未傳送的intent。當服務不再是必需的,並且應用程式能夠簡單地重啟那些未完成的工作時,這是避免服務執行的最安全的選項。
b.START_STICKY;如果系統在onStartCommand()返回後殺死了這個service,會重新建立這個service並且呼叫onStartCommand(),但是不再重新傳送上次最後一個intent,而是使用一個nullintent呼叫onStartCommand(),除非有一些掛起的intent,在此情況下,這些掛起的intent被派送。(適用媒體播放器類似服務,它們不執行命令,但需要一直執行並隨時待命)
c.START_REDELIVER_INTENT;如果系統在onStartCommand()返回後殺死了service,重新建立這個service並且使用上次最後一個intent呼叫onStartCommand().任何掛起的intent都順序地被派送。(這適合於活躍地執行一個工作並且應被立即恢復的服務,比如下載一個檔案)
3.啟動並繫結一個service,如果沒有解綁,呼叫stopService無法殺死服務。
4.unBindService()解除繫結服務,內部呼叫服務的生命週期方法onUnbind(),然後呼叫onDestory()銷燬服務。服務只能被解除繫結一次,如果unBindService方法被呼叫多次,就會出錯。
5.startService啟動服務,呼叫者退出,service依舊還在;bindService繫結服務,呼叫者退出,service也就退出。
二.Service的兩種啟動方式
啟動服務startService程式碼
Intent intent = new Intent(TestActivity.this,TestService.class);
startService(intent);
繫結服務bindService程式碼
private ServiceConnection mTestServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myBinder = (TestService.MyBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
Intent intent = new Intent(TestActivity.this,TestService.class);
bindService(intent,mTestServiceConnection,BIND_AUTO_CREATE);
- 繫結服務,首先要做的事情就是先用Map記錄當前繫結服務所需的一些資訊。 然後啟動服務。
- 解綁服務,先從早前的Map集合中移除記錄,然後停止服務。
- 如果再次解綁,無非就是再到這個map集合中找找有沒有這條記錄,沒有就丟擲服務沒有註冊的異常,也就是早前根本沒有註冊過任何服務。
三.遠端服務
下圖是根據不同方式對服務的分類,這裡重點介紹實現遠端服務
實現遠端服務的程式碼:
AIDL程式碼
// IRemoteService.aidl
package com.example.chenpeng.julyapplication.service;
// Declare any non-default types here with import statements
import com.example.chenpeng.julyapplication.IParticipateCallback;
interface IRemoteService {
int add(int a , int b);
void join(IBinder token,String userName);
void leave(IBinder token);
List<String> getParticipators();
void registerParticipateCallback(IParticipateCallback cb);
void unregisterParticipateCallback(IParticipateCallback cb);
}
建立完AIDL檔案以後,點選Build->Rebuild Project,在app\build\generated\source\aidl\debug中會有對應的ADIL的Java介面檔案。生成如下程式碼:
package com.example.chenpeng.julyapplication.service;
public interface IRemoteService extends android.os.IInterface
{
/** 內部類Stub,繼承Binder */
public static abstract class Stub extends android.os.Binder implements com.example.chenpeng.julyapplication.service.IRemoteService
{
/**Binder的唯一標識,一般用當前的類名錶示*/
private static final java.lang.String DESCRIPTOR = "com.example.chenpeng.julyapplication.service.IRemoteService";
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* 用於將服務端的Binder物件轉換成客戶端所需的AIDL介面型別的物件,這種轉換過程區分程式
* 如果客戶端和服務端位於同一個程式,返回服務端的Stub物件本身;否則返回系統封裝後的Stub.proxy物件
*/
public static com.example.chenpeng.julyapplication.service.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.chenpeng.julyapplication.service.IRemoteService))) {
return ((com.example.chenpeng.julyapplication.service.IRemoteService)iin);
}
return new com.example.chenpeng.julyapplication.service.IRemoteService.Stub.Proxy(obj);
}
/**返回當前Binder物件*/
@Override public android.os.IBinder asBinder()
{
return this;
}
/**
* 這個方法執行在服務端中的Binder執行緒池中,當客戶端發起跨程式請求時,遠端請求會通過系統底層封裝後交由此方法處理。
* 通過code可以確定呼叫哪個方法,如有入參,從data中獲取,方法完成後,如需要返回引數,將引數存入result中。
* 若果,onTransact返回false,則客戶端的請求失敗,因此可以利用這個特徵來做許可權驗證。
* */
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_join:
{
data.enforceInterface(DESCRIPTOR);
android.os.IBinder _arg0;
_arg0 = data.readStrongBinder();
java.lang.String _arg1;
_arg1 = data.readString();
this.join(_arg0, _arg1);
reply.writeNoException();
return true;
}
case TRANSACTION_leave:
{
data.enforceInterface(DESCRIPTOR);
android.os.IBinder _arg0;
_arg0 = data.readStrongBinder();
this.leave(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getParticipators:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<java.lang.String> _result = this.getParticipators();
reply.writeNoException();
reply.writeStringList(_result);
return true;
}
case TRANSACTION_registerParticipateCallback:
{
data.enforceInterface(DESCRIPTOR);
com.example.chenpeng.julyapplication.IParticipateCallback _arg0;
_arg0 = com.example.chenpeng.julyapplication.IParticipateCallback.Stub.asInterface(data.readStrongBinder());
this.registerParticipateCallback(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterParticipateCallback:
{
data.enforceInterface(DESCRIPTOR);
com.example.chenpeng.julyapplication.IParticipateCallback _arg0;
_arg0 = com.example.chenpeng.julyapplication.IParticipateCallback.Stub.asInterface(data.readStrongBinder());
this.unregisterParticipateCallback(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 這個方法執行在客戶端
* 先把引數寫入_data中,接著呼叫transact方法發起RPC(遠端過程呼叫)請求,同時當前執行緒掛起;然後服務端的onTransact方法被呼叫,
* 直到RPC過程返回後,當前執行緒繼續執行,並從_reply中取出RPC過程的返回結果,最後返回_reply中的資料
* */
private static class Proxy implements com.example.chenpeng.julyapplication.service.IRemoteService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int add(int a, int b) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void join(android.os.IBinder token, java.lang.String userName) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder(token);
_data.writeString(userName);
mRemote.transact(Stub.TRANSACTION_join, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void leave(android.os.IBinder token) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder(token);
mRemote.transact(Stub.TRANSACTION_leave, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.util.List<java.lang.String> getParticipators() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<java.lang.String> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getParticipators, _data, _reply, 0);
_reply.readException();
_result = _reply.createStringArrayList();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void registerParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_registerParticipateCallback, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void unregisterParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_unregisterParticipateCallback, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_join = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_leave = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_getParticipators = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_registerParticipateCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_unregisterParticipateCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
}
public int add(int a, int b) throws android.os.RemoteException;
public void join(android.os.IBinder token, java.lang.String userName) throws android.os.RemoteException;
public void leave(android.os.IBinder token) throws android.os.RemoteException;
public java.util.List<java.lang.String> getParticipators() throws android.os.RemoteException;
public void registerParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException;
public void unregisterParticipateCallback(com.example.chenpeng.julyapplication.IParticipateCallback cb) throws android.os.RemoteException;
}
建立在服務端的Service程式碼
public class RemoteService extends Service {
private static final String TAG = "RemoteService";
private List<Client> mClient = new ArrayList<>();
private List<String> mList = new ArrayList<>();
//RemoteCallbackList,幫我自動處理了Link-To-Death的問題
private RemoteCallbackList<IParticipateCallback> mRemoteCallbackList = new RemoteCallbackList<>();
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public void join(IBinder token, String userName) throws RemoteException {
if(findClient(token) < 0){
Client client = new Client(token,userName);
//註冊客戶端死掉的通知
mClient.add(client);
client.mToken.linkToDeath( client,0);
Log.i(TAG, "join: client token = " + token + " 加入client佇列");
notifyParticipate(client.mName,true);
}else{
Log.i(TAG, "join: client成員已存在");
}
}
@Override
public void leave(IBinder token) throws RemoteException {
int index = findClient(token);
if(index >= 0 ){
Client client = mClient.get(index);
//取消註冊
client.mToken.unlinkToDeath( client,0);
mClient.remove(client);
Log.i(TAG, "leave: 刪除token = " + token);
notifyParticipate(client.mName,false);
}
}
@Override
public List<String> getParticipators() throws RemoteException {
int size = mClient.size();
for(int i = 0 ; i < size ; i++){
mList.add(mClient.get(i).mName);
}
return mList;
}
@Override
public void registerParticipateCallback(IParticipateCallback cb) throws RemoteException {
mRemoteCallbackList.register(cb);
}
@Override
public void unregisterParticipateCallback(IParticipateCallback cb) throws RemoteException {
mRemoteCallbackList.unregister(cb);
}
};
//更新通知
private void notifyParticipate(String mName, boolean joinOrLeave) {
int length = mRemoteCallbackList.beginBroadcast();
for(int i = 0 ; i < length ; i++){
try {
//通知回撥
mRemoteCallbackList.getBroadcastItem(i).onParticipate(mName,joinOrLeave);
} catch (RemoteException e) {
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
private int findClient(IBinder token){
int index = -1;
int size = mClient.size();
for(int i = 0 ; i < size ; i++){
if(mClient.get(i).mToken == token){
index = i;
}
}
return index;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: 繫結服務" );
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
mRemoteCallbackList.kill();
}
private class Client implements Binder.DeathRecipient{
IBinder mToken;
String mName;
public Client(IBinder token , String name){
mToken = token;
mName = name;
}
@Override
public void binderDied() {
//客戶端的異常退出
int index = mClient.indexOf(this);
if(index < 0){
return;
}
Log.i(TAG, "binderDied: 異常退出的客戶端名字 = " + mName);
mClient.remove(index);
}
}
}
在服務端的AndroidMinfest.xml中做一下配置
<!-- 將本地服務設定成遠端服務,設定可被其他程式呼叫-->
<service
android:name=".service.RemoteService"
android:process=":remote"
android:exported="true"
>
<intent-filter>
//此處Intent的action最好寫成“伺服器端包名.aidl檔名”的形式
<action android:name="com.example.chenpeng.julyapplication.service.IRemoteService"/>
</intent-filter>
</service>
建立客戶端,一個不同的應用,首先將aidl檔案複製到工程中,位置內容必須原封不動,下面就是client的程式碼
public class MainActivity extends AppCompatActivity {
private Button mBindServiceBtn,mMethodBtn;
private IRemoteService mRemoteService;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mRemoteService = IRemoteService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBindServiceBtn = findViewById(R.id.bindServiceBtn);
mMethodBtn = findViewById(R.id.methodBtn);
mBindServiceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//通過Intent指定服務端的服務名稱和所在包,與遠端Service進行繫結
//引數與伺服器端的action要一致,即"伺服器包名.aidl介面檔名"
Intent intent = new Intent("com.example.chenpeng.julyapplication.service.IRemoteService");
//Android5.0後無法只通過隱式Intent繫結遠端Service
//需要通過setPackage()方法指定包名,否則啟動失敗
intent.setPackage("com.example.chenpeng.julyapplication");
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
}
});
mMethodBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mRemoteService != null){
try {
int sum = mRemoteService.add(2,4);
Toast.makeText(getApplicationContext(),String.valueOf(sum),Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
}
四.IntentService原理
參考這篇IntentService原理
相關文章
- [譯] 關於 Yarn 和 npm 你所需要知道的一切YarnNPM
- [譯] 關於 `ExpressionChangedAfterItHasBeenCheckedError` 錯誤你所需要知道的事情ExpressError
- [譯] 關於 Flutter 頁面路由過渡動畫,你所需要知道的一切Flutter路由動畫
- Java-Mysql你所需要的面試題集內容JavaMySql面試題
- 關於雲原生,這些你要知道
- 關於跨域你需要知道的跨域
- 你需要知道的關於 Go 包的一切Go
- 關於MySQL引數,這些你要知道MySql
- 關於CSS Transition,你需要知道的事CSS
- 關於 v-model 你需要知道的這一切!
- 關於Vue v-model你需要知道的一切Vue
- 關於在Android中使用CMake你所需要了解的一切(一)Android
- 關於ES模組你必須要知道的一些禁忌(一)
- 關於Flutter你要知道的可能都在這兒Flutter
- 關於Http協議,你必須要知道的HTTP協議
- 關於Android模組化你需要知道的Android
- 關於達夢的一些隨筆內容
- 「雜文」開始集訓前你所需要知道的
- MVVM 開發總結 —— Vue 元件(你所需要知道的)MVVMVue元件
- 對於Redis中設定了過期時間的Key,你需要知道這些內容Redis
- 關於在Android中使用CMake你所需要了解的一切(三)Android
- 關於在Android中使用CMake你所需要了解的一切(二)Android
- 關於內容稽核,你需要了解的東西,這裡都有!
- 關於python,你有什麼想要知道的嗎?Python
- [譯] 關於 Angular 動態元件你需要知道的Angular元件
- 關於神經網路:你需要知道這些神經網路
- 關於webpack優化,你需要知道的事(上篇)Web優化
- 關於 SSR 內容一致性的問題
- 關於MySQL核心,一定要知道的!MySql
- [譯] 關於 Angular 的變化檢測,你需要知道的一切Angular
- 【ASK_ORACLE】關於Oracle索引分裂你需要知道的Oracle索引
- 關於專案採購管理,這些你需要知道
- 關於移動端適配,你必須要知道的
- 關於 SAP UI5 控制元件內容的 Excel 匯出功能,如何載入所需的匯出工具庫UI控制元件Excel
- 關於 TDengine 3.0 資料訂閱,你需要知道這些
- 關於進入遊戲行業你需要知道的事遊戲行業
- 關於 iOS 上的 PWA 應用,你需要知道些什麼?iOS
- 關於SCN需要知道的事