Android中的Service與程序間通訊(IPC)詳解
Service
什麼是Service
在後臺長期執行的沒有介面的元件。其他元件可以啟動Service讓他在後臺執行,或者繫結Service與它進行互動,甚至實現程序間通訊(IPC)。例如,可以讓服務在後臺處理網路互動,播放音樂,檔案I/O,或者與ContentProvider互動。
建立一個Service
- 新建一個類,繼承Service,重寫相關方法,如onBind,onUnBind,onCreate,onDestorey。
- 在AndroidManifest.xml中配置Service和相關許可權。
<manifest ... >
...
<application ... >
<service android:name=".MyService" />
...
</application>
</manifest>
開啟服務:
Intent service = new Intent(this,Service.class);
startService(service);
停止服務:
Intent service = new Intent(this,Service.class);
stopService(service);
繫結服務:
private boolean mIsBound = false ;
private ServiceConnection mConnection = new ServiceConnection() {
// 服務連線成功回撥
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder binder = (MyService.MyBinder) service;
}
// 服務失去連接回調
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Event(value = R.id.btn_bind_service)
private void onBindServiceClick(View view) {
bindService(getServiceIntent(), mConnection, Context.BIND_AUTO_CREATE);// 繫結時如果沒有建立Service則自動建立Service。
mIsBound = true;
}
解綁服務:
@Event(value = R.id.btn_unbind_service)
private void onUnbindServiceClick(View view) {
if (!mIsBound) {
ToastUtil.show("未繫結服務");
return;
}
try {
unbindService(mConnection);//注意:ServiceConnection要傳繫結時的ServiceConnection物件,否則會報錯。
} catch (Exception e) {
ToastUtil.show("解除繫結服務失敗");
e.printStackTrace();
}
mIsBound = false;
}
Service的生命週期
public class MyService extends Service {
// 服務建立
@Override
public void onCreate() {
super.onCreate();
}
// 每次startService都會呼叫;通過bindService方式啟動服務,該方法不會被呼叫
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
// 服務銷燬
@Override
public void onDestroy() {
super.onDestroy();
}
// bindService時呼叫,返回一個IBinder物件,用於與Service互動,IBinder就是Service的代理
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
// unbindService時呼叫
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
startService:onCreate——>onStartCommand
stopService:onDestory
注意:服務只會被建立一次,如果服務已經建立,並且沒有銷燬,多次呼叫startService方法,只會執行onStartCommand方法。
bindService:onCreate——>onBind
unbindService:onUnbind——>onDestory
注意:
- 如果多次bindService,onBind方法只會在第一次繫結時被呼叫;同樣,多次startService,onCreate方法也只會在第一次建立時被呼叫;
- 服務只能被解綁一次,服務需要先繫結才能解除繫結,多次解綁會報錯。
- 通過bindService方式啟動的Service,在呼叫unbindService時就會自動銷燬。
- 服務只會停止一次,多次呼叫stopService()的方法無效,但不報錯。
- 每次呼叫startService()開啟服務都會執行onStartCommand()方法。
如何呼叫Service裡的方法
由於系統框架在建立服務的時候會建立與之對應的上下文,直接new出來的服務物件是沒有上下文的,所以直接new服務物件呼叫其方法會報異常。
與Service之間互動都是通過其代理人(IBinder)來間接呼叫Service裡的方法的。
這樣設計主要出於安全考慮,有限的暴露出一些方法,而不是直接返回服務物件,因為服務物件裡可能有一些成員變數和方法不允許外界直接訪問,需要保護起來。
一般IBinder(代理人)也應該設計成私有的,因為是IBinder中的一些資料也需要保護起來,只需要暴露出一些指定的方法,那麼外界如何引用IBinder物件呢?通過介面引用代理人,在介面定義供外界呼叫的方法,讓IBinder類實現該介面。
bindService與startService
bindService與startService的區別:
- 繫結服務:可以間接呼叫服務裡面的方法;如果繫結的Activity被銷燬了,服務也會跟著銷燬。
- 開啟服務:不可以呼叫服務裡面的方法;如果開啟服務的Activity銷燬,服務還可以長期的在後臺執行。
既要保證服務長期在後臺執行,又想去呼叫服務裡面的方法。
步驟:
1. startService(),保證服務在後臺長期的執行;
2. bindService(),獲取中間人(IBinder物件),間接的呼叫服務裡面的方法;
這時,解綁服務並不會導致服務銷燬,服務可長期在後臺執行。
注意:如果服務已經被繫結,直接呼叫stopService()是停不掉的,必須先解除繫結服務再調stopService(),服務才會被銷燬。
示例程式碼
@ContentView(value = R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
private boolean mIsBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
// 服務連線成功回撥
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtil.d(name + " onServiceConnected");
PayService.PayBinder binder = (PayService.PayBinder) service;
binder.pay(100);
}
// 服務失去連接回調
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtil.d(name + " onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//當Activity被銷燬時解綁服務,因為如果已經繫結服務不顯式解綁會報異常。
onUnbindServiceClick(null);
}
private Intent getServiceIntent() {
return new Intent(this, PayService.class);
}
// 啟動服務
@Event(value = R.id.btn_start_service)
private void onStartServiceClick(View view) {
startService(getServiceIntent());
}
// 繫結服務
@Event(value = R.id.btn_bind_service)
private void onBindServiceClick(View view) {
bindService(getServiceIntent(), mConnection, Context.BIND_AUTO_CREATE);// 繫結時如果沒有建立服務則自動建立Service。
mIsBound = true;
}
// 解綁服務
@Event(value = R.id.btn_unbind_service)
private void onUnbindServiceClick(View view) {
if (!mIsBound) {
ToastUtil.show("未繫結服務");
return;
}
try {
unbindService(mConnection);//注意:ServiceConnection要傳繫結時的ServiceConnection物件,否則會報錯。
} catch (Exception e) {
e.printStackTrace();
}
mIsBound = false;
}
// 停止服務
@Event(value = R.id.btn_stop_service)
private void onStopServiceClick(View view) {
stopService(getServiceIntent());
}
}
使用AIDL實現程序間通訊
AIDL(Android Interface Definition Language)用於程序間通訊介面的定義,是一種程序間通訊的規範 。
Service端:
1.New一個aidl檔案在src目錄下
2.在aidl檔案中定義Service中對外開放的介面
// IPayService.aidl
package linchaolong.android.aidldemo.service;
// Declare any non-default types here with import statements
/**
* AIDL Demo
*
* Created by linchaolong on 2016/4/22.
*/
interface IPayService {
void pay(int price);
void startTimer();
void stopTimer();
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*
* 翻譯:
*
* 展示一些可以在AIDL中用作引數和返回值的基本型別。
*
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
aidl語言中沒有許可權修飾符,因為程序間通訊介面許可權肯定是public的。
3.aidl編寫完成後,make一下工程,在build目錄下就會生成該aidl檔案對應的java檔案,比如我這是IPayService.java。
4.在IPayService中有一個Stub靜態類,繼承了Binder和實現了IPayService介面,定義一個Binder類繼承IPayService.Stub並實現相關介面。
@Override
public IBinder onBind(Intent intent) {
if (mBinder == null) {
mBinder = new PayBinder();
}
return mBinder; // 其他應用繫結服務時返回binder物件
}
// Binder
public class PayBinder extends IPayService.Stub {
public void pay(int price) {
PayService.this.pay(price);
}
public void startTimer() {
PayService.this.startTimer();
}
public void stopTimer() throws RemoteException {
PayService.this.stopTimer();
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
// Does nothing
}
}
5.在AndroidManifest.xml配置Service
<service
android:name=".service.PayService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="linchaolong.android.aidldemo.service.PayService" />
</intent-filter>
</service>
到這裡Service端就完成了,其他應用需要呼叫該Service只需要把aidl檔案拷貝到自己工程的src目錄下(make一下),並繫結服務即可得到IBinder物件,通過IBinder物件可以實現與Service的互動。
呼叫示例:
在onServiceConnected回撥裡,呼叫YourServiceInterface.Stub.asInterface(service)把IBinder物件轉換為YourServiceInterface型別。
private IPayService iPayService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 獲取遠端介面例項
iPayService = IPayService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "Service has unexpectedly disconnected");
iPayService = null;
}
};
繫結遠端服務並呼叫IPC方法
/**
* 判斷是否已經繫結遠端服務
*
* @return
*/
private boolean isBinded() {
return mIsBound && iPayService != null;
}
private Intent getServiceIntent() {
return new Intent("linchaolong.android.aidldemo.service.PayService");
}
// 繫結遠端服務
@Event(value = R.id.btn_bind_remote_service)
private void bindRemoteService(View view) {
if (isBinded()) {
showToast("已繫結遠端服務");
return;
}
bindService(getServiceIntent(), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
// 呼叫遠端服務方法
@Event(value = R.id.btn_call_service_pay)
private void callServicePay(View view) {
if (!isBinded()) {
showToast("未繫結遠端服務");
return;
}
try {
// 通過IBinder物件呼叫遠端服務中方法
iPayService.pay(100);
} catch (RemoteException e) {
e.printStackTrace();
}
}
相關推薦
Android中的Service與程序間通訊(IPC)詳解
Service 什麼是Service 在後臺長期執行的沒有介面的元件。其他元件可以啟動Service讓他在後臺執行,或者繫結Service與它進行互動,甚至實現程序間通訊(IPC)。例如,可以讓服務在後臺處理網路互動,播放音樂,檔案I/O,或者與Cont
【Linux】程序間通訊(IPC)之訊號量詳解與測試用例
學習環境centos6.5 Linux核心2.6 程序間通訊概述 1. 程序通訊機制 一般情況下,系統中執行著大量的程序,而每個程序之間並不是相互獨立的,有些程序之間經常需要互相傳遞訊息。但是每個程序在系統中都有自己的地址空間,作業系統通過頁表
Android程序間通訊(IPC)機制Binder簡要介紹和學習計劃
轉載:http://blog.csdn.net/luoshengyang/article/details/6618363/在Android系統中,每一個應用程式都是由一些Activity和Service組成的,這些Activity和Service有可能執行在同一個程序中,也有
【Linux】程序間通訊(IPC)之共享記憶體詳解與測試用例
學習環境centos6.5 Linux核心2.6 什麼是共享記憶體 共享記憶體允許兩個或更多程序訪問同一塊記憶體。當一個程序改變了這塊記憶體中的內容的的時候,其他程序都會察覺到這個更改。 效率: 因為所有程序共享同一塊記憶體,共享記憶體在各種程序
Linux程序間通訊(IPC)方式總結
程序間通訊概述 程序通訊的目的 資料傳輸 一個程序需要將它的資料傳送給另一個程序,傳送的資料量在一個位元組到幾M位元組之間 共享資料 多個程序想要操作共享資料,一個程序對共享資料 通知事件 一個程序需要向另一個或一組程序傳送訊息,通知它(它們)
linux程序間通訊(IPC)小結
linux IPC型別 1、匿名管道 2、命名管道 3、訊號 4、訊息佇列 5、共享記憶體 6、訊號量 7、Socket 1、匿名管道 過程: 1、管道實質是一個核心緩衝區,先進先出(佇列)讀取緩衝區記憶體資料 2、一個數據只能讀一次,讀完後在緩衝區就不存在
深刻理解Linux程序間通訊(IPC)(轉)
序linux下的程序通訊手段基本上是從Unix平臺上的程序通訊手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力 AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟體釋出中心)在程序間通訊方面的側重點有所不同。前者對Unix早期的程序間通訊手 段進行了系統的改進和擴充,形成了“system
程序間通訊(IPC)介紹
程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。 IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個程序IPC。 以Linux中的C
程序間通訊(IPC)——管道通訊
IPC(Inter-Process Communication)程序間通訊,提供了各種程序間通訊的方法。在Linux C程式設計中有幾種方法 (1) 半雙工Unix管道 (2) FIFOs(命
QT之程序和程序間通訊(IPC)
程序是作業系統的基礎之一。一個程序可以認為是一個正在執行的程式。我們可以把程序當做計算機執行時的一個基礎單位。關於程序的討論已經超出了本章的範疇,現在我們假定你是瞭解這個概念的。 在 Qt 中,我們使用QProcess來表示一個程序。這個類可以允許我們的應用程式開啟一個新的外部程式
程序間通訊(IPC)——訊息佇列
IPC(Inter-Process Communication)程序間通訊,提供了各種程序間通訊的方法。在Linux C程式設計中有幾種方法 (1) 半雙工Unix管道 (2) FIFOs(命名管道) (3) 訊息佇列 (4) 訊號量 (5) 共
【Qt】Qt之程序間通訊(IPC)【轉】
簡述 程序間通訊,就是在不同程序之間傳播或交換資訊。那麼不同程序之間存在著什麼雙方都可以訪問的介質呢?程序的使用者空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享記憶體區。但是,系統空間卻是“公共場所”,所以核心顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪問的外設了。在這個意義上,兩
程序間通訊(IPC)-管道、訊息佇列、共享記憶體、訊號、訊號量、套接字
多程序:首先,先來講一下fork之後,發生了什麼事情。由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是:因為一
Linux系統下-程序間通訊(訊息佇列-詳解)
Linux下程序間通訊方式: # 管道( pipe ):管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的程序間使用。程序的親緣關係通常是指父子程序關係。 # 有名管道 (named pipe) : 有名管道也是半雙工的通訊方式,但是它允許無親緣關係程序
程序間通訊(IPC)
程序間通訊IPC,也就是Inter-Process Communication的縮寫。 首先我們明白一個程序其實就是一個狹義上的程式。 一個伺服器也就是一個程序。比如客戶端和伺服器的連線就是兩個程序在通訊,只是這兩個程序並不在同一臺計算機上,它們程序間
【Linux】程序間通訊(IPC)之訊息佇列詳解及測試用例
學習環境 Centos6.5 Linux 核心 2.6 什麼是訊息佇列? 訊息佇列是SystemV版本中三種程序通訊機制之一,另外兩種是訊號量和共享儲存段。訊息佇列提供了程序間傳送資料塊的方法,而且每個資料塊都有一個型別標識。訊息佇列是基於訊息的,而管
Linux程序全解11——程序間通訊(IPC)概述
以下內容源於朱有鵬《物聯網大講堂》的課程學習整理,如有侵權,請告知刪除。 1、為什麼需要程序間通訊? (1)程序間通訊(IPC) 指的是2個任意程序之間的通訊。 (2)同一個程序在一個地址空間中 同一個程序的不同模組(不同函式、不同檔案)之間的通訊很簡單很多時候都是全
深刻理解Linux程序間通訊(IPC)
序 linux下的程序通訊手段基本上是從Unix平臺上的程序通訊手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟體釋出中心)在程序間通訊方面的側重點有所不同。前者對Unix早期的程序間通訊手段進行了
使用 AIDL 實現客戶端和服務的程序間通訊(IPC)
1. 使用步驟 AIDL 的意思是 Android 介面定義語言。利用它來定義程序間通訊時雙方認可的程式設計介面。 第一步:建立 .aidl 檔案 AIDL 介面方法中支援的引數型別: 8 個基本資料型別 String CharSequence Lis
Andorid程序間通訊(IPC)——Messenger
Messenger可以翻譯為信使,通過它可以在不同的程序中傳遞Message物件,在Message中放入我們需要傳遞的資料, 這樣就可以輕鬆的實現程序間通訊了 Android中的 IPC 方式 1.使用Bundle 2.使用檔案共享 3.使用Mess