Android AIDL:服务到 Activity 通信

Android AIDL: Service-to-Activity communication

我尝试实施 Android AIDL 通信策略。 我有一个 Activity 和一个 Service。 我的Activity可以成功"talk"到我的服务,但是反向过程好像不行。

总而言之,ActivityService运行在不同的进程中,不能共享任何数据都会抛出 IBinder 接口。 因此 onServiceConnected() 方法改为接收 AIDL 接口。 该接口是服务端实现的,旨在被使用(调用)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);
}

服务实现 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 并有一个 "watcher" Activity 端不断检查计数器。 但我更想了解为什么它不起作用,以及使用 AIDL 的正确方法是什么。

总结

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");
       }
    });
}