有時間,重新複習下,把以前做過的server 相關 整理下。當時可還是花了些時間查代碼的。
從最簡單的server 到支持回調的server。
1:最簡單的server,指只要應用的人來呼叫下,啓動他,沒別的交互的。
server端注意事項:
生成一個Service 的繼承類,默認重載onBind函數。(後面的代碼需要修改這個函數) 現在不用管他。
在AndroidManifest.xml裏面申明這個類
<service android:name=".TestServer" >
<intent-filter>
<action android:name="TestServer" />
<category android:name="android.intent.category.DEFAULT"
/>
</intent-filter>
</service>
client 端:
Intent i = new Intent();
i.setClassName( "com.test.testserver",
"com.test.testserver.TestServer" );
startService(i);
這樣一個簡單的引用就完成了。
注:這樣啓動的service是會一直存在的,不管客戶端的情況。除非你調用stopService(Intent)。
另外,也可以用bindService(i, null, Context.BIND_AUTO_CREATE);來啓動service,這樣這個service是依附在client 上的,如果客戶端關掉,他也會關掉。bindService(i, null, Context.BIND_AUTO_CREATE);
2: 支持aidl的service,支持函數調用 (這樣不涉及到原理,相關android 原理我準備下一篇文章討論)
server端注意事項:
搞一個aidl文件,這個類似java的 interface
interface Itestserver {
int testAdd(int i, int j);
}
這樣就會生成一個自動interface
public interface Itestserver extends android.os.IInterface
和一個類
public static abstract class Stub extends android.os.Binder implements com.arcsoft.testserver.Itestserver
這樣在代碼裏面生成新建立這樣一個對象,並實現定義的函數:
private final Itestserver.Stub mBinder = new Itestserver.Stub() {
@Override
public int testAdd(int i, int j) throws RemoteException {
// TODO Auto-generated method stub
return i+j;
}
};
修改OnBinder函數
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mBinder;
}
client 端:
把aidl 也copy過去,這樣也得到自動的Itestserver
實現一個ServiceConnection的子類。
class AdderServiceConnection implements ServiceConnection
{
public void onServiceConnected(ComponentName className,
IBinder boundService )
{
service = Itestserver.Stub.asInterface((IBinder)boundService);
//Log.d( "ADDERSERVICECLIENT","onServiceConnected" );
}
public void onServiceDisconnected(ComponentName className)
{
service = null;
// Log.d( "ADDERSERVICECLIENT","onServiceDisconnected" );
}
};
調用binder方式來啓動service
conn = new AdderServiceConnection();
Intent i = new Intent();
i.setClassName( "com.arcsoft.testserver",
"com.arcsoft.testserver.TestServer" );
bindService( i, conn, Context.BIND_AUTO_CREATE);
這樣就可以簡單的調用接口了:
int t = service.testAdd(5,6);
3: 支持回調的service
如果涉及到類似UI刷新的問題,就必需支持回調。
要支持回調,有兩個需要注意的地方:
1:新定義一個回調AIDL,注意這個AIDL對應的stub要放在客戶端來實現,調用在service端。
2:使用RemoteCallbackList,來得的一個安全的調用。
服務器端:
新的AIDL
oneway interface ItestserverCallback {
void processCompleted(int Retvalue);
}
修改前面的AIDL,增加註冊回調接口
interface Itestserver {
int testAdd(int i, int j);
void registerCallback(in ItestserverCallback cb);
void unregisterCallback(in ItestserverCallback cb);
}
在代碼中增加新的對象:
final RemoteCallbackList<ItestserverCallback> mCallbacks = new RemoteCallbackList<ItestserverCallback>();
同時實現新的函數:
@Override
public void registerCallback(ItestserverCallback cb)
throws RemoteException {
// TODO Auto-generated method stub
if (cb != null)
mCallbacks.register(cb);
}
@Override
public void unregisterCallback(ItestserverCallback cb)
throws RemoteException {
// TODO Auto-generated method stub
if (cb != null)
mCallbacks.unregister(cb);
}
這樣就可以在server端使用這個回調了。
如在某個異步函數結束的時候調用以下函數
void processend(final int res) {
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
mCallbacks.getBroadcastItem(i).processCompleted(res);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
}
客戶端:
同樣引入新的AIDL
同時實現register的stub,並且註冊進去
private final ItestserverCallback.Stub mBinder = new ItestserverCallback.Stub() {
@Override
public void processCompleted(int Retvalue) throws RemoteException {
// TODO Auto-generated method stub
mHanler.sendMessage(mHanler.obtainMessage(1, Retvalue, 0));
}
};
try {
service.registerCallback(mBinder);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
service.unregisterCallback(mBinder);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
這樣就可以通過管理handler,來處理事務了。
加一張流程圖,解釋整個RPC流程。