基本介紹
Service是一個應用程序組件,四大組件之一,它能夠在後臺執行一些耗時較長的操作,並且不提供用戶界面。服務能被其它應用程序的組件啓動,即使用戶切換到另外的應用時還能保持後臺運行。此外,應用程序組件還能與服務綁定,並與服務進行交互,甚至能進行進程間通信(IPC)。
使用方式
Service有常見的兩種啓動方式,Started 和Bound 方式。
Started 方式
如果一個應用程序組件(比如一個activity)通過調用startService()來啓動服務,則該服務就是被“started”了。
一旦被啓動,服務就能在後臺一直運行下去,即使啓動它的組件已經被銷燬了。
通常,started的服務執行單一的操作並且不會向調用者返回結果。比如,它可以通過網絡下載或上傳文件。當操作完成後,服務應該自行終止。
執行順序: onCreate() -> onStartCommand() ->onDestroy();
銷燬方式 stopService()
區別: startService()之後,無論啓動的組件是否仍然存在,沒有調用stopService()方法,Service仍然存在。
/**
* 啓動服務
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:20
*/
public void startService(View view) {
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
/**
* 關閉服務
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:20
*/
public void stopService(View view) {
Intent intent = new Intent(this, MyService.class);
stopService(intent);
}
Bound 方式
如果一個應用程序組件通過調用bindService()綁定到服務上,則該服務就是被“bound”了。
bound服務提供了一個客戶端/服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至可以利用進程間通信(IPC)跨進程執行這些操作。
綁定服務的生存期和被綁定的應用程序組件一致。 多個組件可以同時與一個服務綁定,不過所有的組件解除綁定後,服務也就會被銷燬。
執行順序: onCreate() -> onBind() ->onDestroy();
銷燬方式 unbindService()
注意:通過unbindService()取消Service需要判定是否bind,否則報異常
區別: bindService()即將調用綁定的組件與這個Service捆綁在一起,組件銷燬了Service也被銷燬,類似從屬關係。
Bound方式Service與Activity通訊
1.MyService中的onBind()返回IBind子類實例。
2.ServiceConnection的onServiceConnected()方法拿出IBinder,向下強轉爲MyService中的IBind子類,即可對Service進行操作。
private ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("info", "onServiceConnected: ==++ 服務連接");
MyService.MyBinder myBinder = (MyService.MyBinder) service;
myBinder.doSomething();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("info", "onServiceDisconnected: ==++ 服務取消連接");
}
};
// 標記服務是否綁定
private boolean isBind = false;
/**
* 綁定服務
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:27
*/
public void bindService(View view) {
Intent intent = new Intent(this, MyService.class);
bindService(intent, mServiceConn, BIND_AUTO_CREATE);
isBind = true;
}
/**
* 取消綁定服務
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:28
*/
public void unbindService(View view) {
if (isBind) {
isBind = false;
unbindService(mServiceConn);
}
}
MyService
/**
* 自定義Service
*
* @author fengzhen
* @version 1.0, 2017/7/21
*/
public class MyService extends Service {
@Override
public void onCreate() {
Log.i("info", "onCreate: ==++ 服務創建");
Log.i("info", "onCreate: ==++ 當前線程:" + Thread.currentThread().getName());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("info", "onStartCommand: ==++ 服務啓動");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i("info", "onDestroy: ==++ 服務銷燬");
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i("info", "onBind: ==++ 綁定服務");
return new MyBinder();
}
public class MyBinder extends Binder {
public void doSomething() {
Log.i("info", "doSomething: ==+++ 做具體的事");
}
}
}
運行線程
通過驗證可以發現,Service和Activity一樣,運行在主線程,所以在使用是需要創建一個新的線程完成服務的工作。
也可以使用其子類:IntentService
IntentService
創建一個缺省的工作(worker)線程,它獨立於應用程序主線程來執行所有發送到onStartCommand()的intent。
創建一個工作隊列,每次向你的onHandleIntent()傳入一個intent,這樣你就永遠不必擔心多線程問題了。
在處理完所有的啓動請求後,終止服務,因此你就永遠不需調用stopSelf()了。
提供缺省的onBind()實現代碼,它返回null。
提供缺省的onStartCommand()實現代碼,它把intent送入工作隊列,稍後會再傳給你的onHandleIntent()實現代碼。
/**
* Service服務擴展類
*
* @author fengzhen
* @version v1.0, 2017/7/21
*/
public class MyIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
* <p>
* Used to name the worker thread, important only for debugging.
*/
public MyIntentService() {
super("MyIntentService");
}
/**
* IntentService從缺省的工作線程中調用本方法,並用啓動服務的intent作爲參數
* 本方法返回後,IntentService將適時終止這個服務。
* <p>
* 再次方法操作需要在子線程做的,使用循環的方式,直到任務完成
*
* @author fengzhen
* @version v1.0, 2017/7/21 17:05
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.i("info", "onCreate: ==++ 當前線程:" + Thread.currentThread().getName());
int i = 0;
while (i < 10) {
i++;
// doSomething
}
}
}
進程間通信(IPC)
使用AIDL來進行進程間通信(IPC)
AIDL(Android Interface Definition Language):Android接口定義語言
1.更改Service在xml配置
<service android:name=".MyService"
android:process=":remote">
<intent-filter>
<action android:name="com.hftsoft.servicedemo.MyAidlInterface"/>
</intent-filter>
</service>
2.創建AIDL文件
這裏參數類型只能使用basecTypes中的所有參數類型
AS創建AIDL文件只有需要點擊 mudel 旁小錘子圖標 Make Project (Ctrl + f9)
interface MyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
/**
* 自定義簡單方法
*/
String getString(int a);
}
3.綁定Activity中實現
private MyAidlInterface mMyAidlInterface;
/**
* PIC Conn
*
* @author fengzhen
* @version v1.0, 2017/7/21 18:16
*/
private ServiceConnection mServiceConnRemote = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMyAidlInterface = MyAidlInterface.Stub.asInterface(service);
try {
String string = mMyAidlInterface.getString(5);
Log.i("info", "onServiceConnected: ==++" + string);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
// 標記服務是否綁定
private boolean isBind = false;
/**
* 綁定服務 IPC
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:27
*/
public void bindService(View view) {
Intent intent = new Intent("com.hftsoft.servicedemo.MyAidlInterface");
intent.setPackage(this.getPackageName());
bindService(intent, mServiceConnRemote, BIND_AUTO_CREATE);
isBind = true;
}
/**
* 取消綁定服務 IPC
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:28
*/
public void unbindService(View view) {
if (isBind) {
isBind = false;
unbindService(mServiceConnRemote);
}
}