我有一个应用程序(客户端)使用AIDL对第二个应用程序(服务器)执行远程调用。每个通过Binder的调用都在服务器应用程序中以AIDL解决方案设计的不同线程(TID)执行。
是否可以在Server应用程序中执行所有调用只在一个线程中执行?我们可以控制所有呼叫者(客户端应用程序),他们将以串行模式执行呼叫,我们不需要服务器应用程序以多线程方式执行呼叫。
因此,如果客户端应用程序1对需要30秒及之前的方法执行远程调用,则第二个客户端应用程序2执行对相同方法(或甚至其他方法)的调用,我们希望执行第二次调用在第一次调用的同一个线程中。
Messenger现在不是一个选择。
===更新了====
消息不是一个选项(暂时)。更多细节:我们有一种服务,有两种类型的粘合剂:a)TransacionManager(tm)和DAOImpl(dao)。
我们首先在客户端调用tm.begin(),甚至同步处理它,在服务端,它在线程池(android aidl代码)的线程中执行。该线程TID#1在SQLite数据库中执行begin transaction命令。
然后我们同步调用dao.selectNextId() - 并且在服务中它在TID#2中执行。在selectNextId()方法中,我们检查数据库是否为inTransaction,并返回false。
为了确认线程是问题,我们将所有内容都放在一个调用另一个绑定器(allDAO)中。因此,当我们调用allDAO.do()时,它在另一个线程TID#3中的服务端运行,并执行begin transc并插入非常好。
不确定问题是SQLite将不同的线程作为单独的请求进行管理(如何处理)......我们只希望服务(使用aidl)每次都在同一个线程中执行来自任何客户端的每次调用。
答案 0 :(得分:0)
我正在与Mario合作解决此问题并使用@ pskink的code代码段解决了多线程问题。
问题解决了将所有aidl调用重定向到主线程。为此,我们使用了一个接收MainLooper的Handler和一个扩展CountDownLatch的Runnable。
我们的解决方案的代码如下:
// SyncHandler.class
public class SyncHandler {
private SyncRunnable mRunnable;
public SyncHandler() {
super();
}
public SyncHandler start(@NonNull SyncRunnable runnable) {
mRunnable = runnable;
final Looper looper = Looper.getMainLooper();
Handler handler = new Handler(looper);
handler.post(mRunnable);
try {
mRunnable.await();
} catch (InterruptedException e) {
Log.e(this, "Error when SyncHandler was awaiting.", e);
}
return this;
}
public static class ReturnValue<T> {
public T value;
}
}
// SyncRunnable.class
public final class SyncRunnable extends CountDownLatch implements Runnable {
private Runnable mRunnable;
public static SyncRunnable create(Runnable runnable) {
return new SyncRunnable(runnable);
}
private SyncRunnable(Runnable runnable) {
super(1);
mRunnable = runnable;
}
@Override
public void run() {
Log.d(this, "SyncRunnable.run() executed on thread: " + Thread.currentThread());
mRunnable.run();
countDown();
}
}
//And the database call:
// TransactionManager.class
public synchronized void begin(final int ownerHashCode, String ownerName) throws RemoteException {
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
@Override
public void run() {
if (mOwner == null) {
mOwner = ownerHashCode;
for (Database database : mDatabases) {
database.beginTransaction();
}
} else if (mOwner == ownerHashCode) {
throw new DbTransactionException("Error: TransactionOwner == owner");
}
}
}));
}
// DaoHelper.class
public synchronized long insert(Dao dao) {
final SyncHandler.ReturnValue<Long> value = new SyncHandler.ReturnValue<>();
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
@Override
public void run() {
Log.d(DaoHelper.this, "db.inTransaction: " + mManagerDb.getDatabase().inTransaction());
value.value = mManagerDb.getDatabase().insert(mTable, null, mContentValues);
}
}));
return value.value;
}