【问题标题】:Android AIDL: Service-to-Activity communicationAndroid AIDL:服务到活动的通信
【发布时间】:2016-12-19 05:53:33
【问题描述】:

我尝试实现 Android AIDL 通信策略。 我有一个 Activity 和一个 Service。 我的Activity 可以成功地与我的Service“对话”,但相反的过程似乎不起作用。

总而言之,由于ActivityService运行在不同的进程中,它们不能共享任何数据抛出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");
    }
}

我也尝试了一些变化,例如:

  1. appendToView("*** Hey... 运行到runOnUiThread()
  2. 使用另一个处理程序延迟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

标签: java android aidl


【解决方案1】:

总结

要更改的 2 个语句。

DemoService.java

final Handler handler = new Handler(DemoService.this.getMainLooper());

MainActivity.java

public void appendToView(String text) {
   view.post(new Runnable() {
       @Override
       public void run() {
           view.append(text + "\n");
       }
    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多