我尝试实现一种Android AIDL通信策略。我有一个Activity和一个Service,我的Activity可以成功地与我的Service进行通信,但反过来好像不起作用。
简而言之,由于Activity和Service运行在不同的进程中,它们无法通过IBinder接口共享任何数据。因此,onServiceConnected()方法接收到一个AIDL接口,这个接口是在Service端实现的,旨在被Activity端使用(调用)。我使用这个接口去注册另一个AIDL,这个新的AIDL是在Activity端实现的,并通过AIDL接口从Service端调用,它充当监听器。不幸的是,这个新AIDL的方法似乎没有被调用。
Service在AndroidManifest.xml中运行在自己的进程中,这得益于以下行:
简而言之,由于Activity和Service运行在不同的进程中,它们无法通过IBinder接口共享任何数据。因此,onServiceConnected()方法接收到一个AIDL接口,这个接口是在Service端实现的,旨在被Activity端使用(调用)。我使用这个接口去注册另一个AIDL,这个新的AIDL是在Activity端实现的,并通过AIDL接口从Service端调用,它充当监听器。不幸的是,这个新AIDL的方法似乎没有被调用。
Service在AndroidManifest.xml中运行在自己的进程中,这得益于以下行:
AndroidManifest.xml
<service android:name=".DemoService" android:process=":DemoServiceProcess" />
我有两个AIDL文件,其中一个知道另一个。
IAidlActivity.aidl
package app.test.aidldemo;
interface IAidlActivity {
void publish(int count);
}
IAidlService.aidl
package app.test.aidldemo;
import app.test.aidldemo.IAidlActivity;
interface IAidlService {
void startCounter();
void register(IAidlActivity activity);
}
这个服务实现了 onBind()
方法并运行一个负责增加计数器的 handler。
DemoService.java
package app.test.aidldemo;
import [...]
public class DemoService extends Service
{
protected IAidlActivity aidlActivity;
@Override
public IBinder onBind(Intent intent)
{
return new IAidlService.Stub() {
@Override
public void startCounter() {
DemoService.this.startJob();
}
@Override
public void register(IAidlActivity activity) {
DemoService.this.aidlActivity = activity;
}
};
}
public void startJob() {
final Handler handler = new Handler();
handler.post(new Runnable() {
protected int count = 0;
@Override
public void run() {
if (count < 500) {
count++; // increment counter
try { // then publish it to view
DemoService.this.aidlActivity.publish(count); // interface, implemented activity-side
} catch (RemoteException e) {}
handler.postDelayed(this, 2000); // 2sec.
}
}
});
}
}
Activity 只包含一个 TextView。
它与 Service 开始绑定,并定时更新视图。
当调用 publish()
时,它也应该更新视图。
但这并没有发生。
MainActivity.java
package app.test.aidldemo;
import [...]
public class MainActivity extends Activity {
protected TextView view;
protected ServiceConnection connection;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
view = new TextView(this);
setContentView(view);
appendToView("Let's go!");
connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IAidlService aidlService = IAidlService.Stub.asInterface(service);
appendToView("IAidlService accessed");
IAidlActivity.Stub aidlActivity = new IAidlActivity.Stub() {
@Override
public void publish(int count) {
appendToView("*** Hey, new count is: " + count + "!! ***");
}
};
appendToView("IAidlActivity created");
try {
aidlService.register(aidlActivity);
aidlService.startCounter(); // interface, implemented service-side
}
catch (RemoteException e) { appendToView(e.toString()); }
}
@Override
public void onServiceDisconnected(ComponentName name) {}
};
Intent intent = new Intent(MainActivity.this, DemoService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
@Override
public void onDestroy() {
unbindService(connection);
super.onDestroy();
}
public void appendToView(String text) {
view.append(text + "\n");
}
}
我也尝试了一些变化,比如:
- 将
appendToView("*** Hey...
放进runOnUiThread()
- 使用另一个 handler +
postDelayed()
来延迟bindService()
如果以上方法都不行,我的备选方案就是只使用 IAidlService 并在 Activity 端设置一个“观察者”来不断检查计数器的值。但我更想知道为什么它不能正常工作,以及正确使用 AIDL 的方法是什么。
register()
) 触发的,所以我并不感到意外。似乎当 Service 进程启动它时会出现问题。 - gabrielstartJob
函数内添加一些Log.d
语句并进行跟踪。 - pskinkrun()
没有运行。现在我正在使用new Handler(DemoService.this.getMainLooper())
创建处理程序。所以run()
现在可以运行了。但是当应用程序在前台时,视图仍然没有更新。我需要保持返回按钮并重新选择应用程序才能看到所有新条目!我尝试使用View.invalidate()
但无济于事。 - gabrielview.append()
(从appendToView
)包装在view.post(new Runnable() {...})
中。如果它能够很好地与我的初始应用程序配合使用,我将关闭问题。 - gabrielview.post(new Runnable() { view.append() })
解决了问题。感谢@pskink帮助我坚持下去。 - gabriel