遠程Service與Activity的交互(AIDL的應用)
首先我們先上一個通俗的情景:在應用1中Activity綁定了一個Service,并且設置了一些值,此時我們想在應用2中調(diào)用該service并且想得到該值應該怎么做?我們都知道每個應用程序都運行在各自的進程中,并且android平臺是不允許不同進程間進行直接的對象數(shù)據(jù)等傳遞的。如果必須進行跨進程之間的數(shù)據(jù)傳遞,那么我們就應該使用AIDL(Android Interface Definition Language)。
AIDL只支持方法,不能定義靜態(tài)成員,并且方法也不能有類似public等的修飾符;AIDL運行方法有任何類型的參數(shù)和返回值,在java的類型中,以下的類型使用時不需要導入包(import),基本數(shù)據(jù)類型、String、Map、List.當然為了避免出錯,建議只要使用了,就導入包。
使用AIDL的步驟:
服務端(提供服務):
第1步:定義一個*.aidl文件,該文件里是符合aidl語言規(guī)范的接口定義,里面定義了外部應用可以訪問的方法。當我們保存該文件的時候,eclipse會自動為我們在gen文件夾下生成一個相應的java接口文件。如:
- package com.android.macdroid;
- interface IPerson {
- void setValue(String name);
- String getValue();
- }
第2步:實現(xiàn)AIDL文件生成的JAVA接口Stub
- class Person extends IPerson.Stub {
- private String name;
-
- @Override
- public void setValue(String name) throws RemoteException {
- this.name = name ;
- }
-
- @Override
- public String getValue() throws RemoteException {
- return name;
- }
-
- }
第3步:定義一個自己的service, 并將其注冊到androidManifest.xml文件中,例如:
- public class ServiceC extends Service {
- private Stub iPerson = new Person();
- @Override
- public IBinder onBind(Intent arg0) {
- Log.i("service", "onBind...");
- return iPerson;
- }
- }
- <service android:name="com.android.macdroid.ServiceC" >
- <intent-filter >
- <action android:name="forServiceAidl" > </action>
- </intent-filter>
- </service>
我們都知道,在實現(xiàn)自己的service時,為了其他應用可以通過bindService來和我們的service進行交互,我們都要實現(xiàn)service中的onBind()方法,并且返回一個繼承了Binder的內(nèi)部類;在這里,eclipse自動為我們生成的RemoteServiceInterface.java中有一個實現(xiàn)了Binder的內(nèi)部類,RemoteServiceInterface.Stub。AIDL要求我們,在這里不能再直接去實現(xiàn)Binder類了,而是去實現(xiàn),AIDL提供給我們的Stub類。 實現(xiàn)stub類的同時,AIDL還要求我們同時實現(xiàn)我們在接口中定義的各種服務的具體實現(xiàn)。至此為止,我們的服務端已經(jīng)和我們的aidl文件綁定到一起了哦。
同一個應用中的Activity為該Service中賦值:
- package com.android.macdroid;
-
- import android.app.Activity;
- import android.app.Service;
- import android.content.ComponentName;
- import android.content.DialogInterface;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.widget.Button;
- import android.widget.Toast;
- import com.android.macdroid.IPerson;
-
- public class AIDLTestActivity extends Activity {
-
- private IPerson iPerson;
- private Button bindBtn, unbindBtn;
-
- private ServiceConnection conn = new ServiceConnection() {
-
- // 斷開連接時調(diào)用
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- }
-
- // 連接時調(diào)用
- @Override
- public void onServiceConnected(ComponentName arg0, IBinder binder) {
- iPerson = IPerson.Stub.asInterface(binder);
- if (iPerson != null) {
- try {
- iPerson.setValue("Service AIDL");
- Toast.makeText(AIDLTestActivity.this, "賦值成功!",
- Toast.LENGTH_LONG).show();
- } catch (RemoteException e) {
- e.printStackTrace();
- Toast.makeText(AIDLTestActivity.this, "賦值失敗!",
- Toast.LENGTH_LONG).show();
- }
- }
- }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- bindBtn = (Button) findViewById(R.id.bindBtn);
- unbindBtn = (Button) findViewById(R.id.unbindBtn);
- bindBtn.setOnClickListener((android.view.View.OnClickListener) listener);
- bindBtn.setOnClickListener(listener);
- unbindBtn.setOnClickListener(listener);
- }
- private OnClickListener listener = new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- switch (v.getId()) {
- case R.id.bindBtn:
- //本應用中需要在manifest中配置RemoteService
- bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);
- break;
- case R.id.unbindBtn:
- unbindService(conn);
- break;
- default:
- break;
- }
- }
-
- };
-
- }
客戶端:
第1步:客戶端要想使用該服務,肯定要先知道我們的服務在aidl文件中到底對外提供了什么服務,對吧?所以,第一步,我們要做的就是,將aidl文件拷貝一份到客戶端的程序中(這里一定要注意,包路徑要和服務端的保持一致哦,例如服務端為cn.com.chenzheng_java.remote.a.aidl,那么在客戶端這邊也應該是這個路徑)。
第2步:我們都知道,想要和service交互,我們要通過bindService方法,該方法中有一個ServiceConnection類型的參數(shù)。而我們的主要代碼便是在該接口的實現(xiàn)中。
第3步:在ServiceConnection實現(xiàn)類的onServiceConnected(ComponentName name, IBinder service)方法中通過類似remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);方式就可以獲得遠程服務端提供的服務的實例,然后我們就可以通過remoteServiceInterface 對象調(diào)用接口中提供的方法進行交互了。(這里的關(guān)鍵是通過*.Stub.asInterface(service);方法獲取一個aidl接口的實例哦)
我們前面在服務端中說過了,必須提供一個intent-filter來匹配請求是否合法,所以我們在客戶端訪問服務的時候,還必須傳遞包含了匹配action的Intent哦。
客戶端中使用服務端中的service范例:
- private ServiceConnection conn = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- }
- //因為有可能有多個應用同時進行RPC操作,所以同步該方法
- @Override
- public synchronized void onServiceConnected(ComponentName arg0, IBinder binder) {
- //獲得IPerson接口
- person = IPerson.Stub.asInterface(binder);
- if(person != null){
- try {
- //RPC方法調(diào)用
- String name = person.getValue();
- Toast.makeText(DemoAIDLActivity.this, "遠程進程調(diào)用成功!值為 : "+name, Toast.LENGTH_LONG).show();
- } catch (RemoteException e) {
- e.printStackTrace();
- Toast.makeText(DemoAIDLActivity.this, "遠程進程調(diào)用失敗! ", Toast.LENGTH_LONG).show();
- }
- }
- }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btn = (Button)findViewById(R.id.btn);
- btn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View arg0) {
- //該應用中不需要在manifest中配置RemoteService
- bindService(new Intent("forServiceAidl"), conn, Service.BIND_AUTO_CREATE);
- }
- });
- }
參考博客:Android Service學習之AIDL, Parcelable和遠程服務
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。