【发布时间】:2016-12-19 05:53:33
【问题描述】:
我尝试实现 Android AIDL 通信策略。 我有一个 Activity 和一个 Service。 我的Activity 可以成功地与我的Service“对话”,但相反的过程似乎不起作用。
总而言之,由于Activity和Service运行在不同的进程中,它们不能共享任何数据抛出IBinder接口。
所以onServiceConnected() 方法接收一个AIDL 接口。
该接口是在Service端实现的,旨在被使用(称为)Activity端。
我用这个接口来register()另一个AIDL。
这个新的AIDL是在Activity端实现的,通过AIDL接口调用Service端。
它就像一个听众。
不幸的是,这个新的 AIDL 的方法似乎没有被调用。
Service 在自己的进程中运行,这要归功于AndroidManifest.xml 中的以下行:
AndroidManifest.xml
<service android:name=".DemoService" android:process=":DemoServiceProcess" />
我有 2 个 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);
}
Service 实现onBind() 并运行一个处理程序 负责递增计数器。
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 启动 bounding 并不时更新视图。
它还应该在调用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() - 使用另一个处理程序延迟
bindService()+postDelayed()
我的后备技术是只使用 IAidlService 并有一个“观察者”活动端不断检查计数器。 但我更想了解它为什么不起作用,以及使用 AIDL 的正确方法是什么。
【问题讨论】:
-
仅用于在 register() 方法中测试调用 publish()
-
@pskink 好电话。是的,这个有效。调用是由Activity进程触发的(通过
register()),所以我并不感到意外。看起来它在服务进程启动它时失败了。 -
在
startJob中添加一些Log.d并跟踪它 -
好的。花了我一段时间。看起来
run()没有在这个演示中运行。现在我正在使用new Handler(DemoService.this.getMainLooper())创建处理程序。所以run()现在运行。但是当应用程序在前台时,视图仍然没有更新。我需要保持后退按钮并再次选择应用程序以查看所有新条目!我尝试使用View.invalidate()无济于事。 -
看来我最终掌握了它。我将
view.append()(来自appendToView)包裹在view.post(new Runnable() {...})中。我会看看它是否适用于我的初始应用程序,如果可以,请关闭 question。