7

リモート サービス (~40,000/秒) と高速に通信するプログラムを Android で作成しようとしていますが、すべての Android IPC はこのタスクを達成するには不十分なようです。私の最初の試みは、標準の Messenger システムを使用したもので、1 秒あたり約 2,000 回を超える処理ができませんでした。同様に悪いのは、断続的なラグで中断されているように見えることでした。

MainActivity (メッセンジャーでテスト)

public class MainActivity extends Activity implements ServiceConnection{

    Messenger mServiceMessenger;
    Messenger mClientMessenger = new Messenger(new ClientHandler());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this,TestService.class);
        bindService(intent,this, Context.BIND_AUTO_CREATE);
    }


    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mServiceMessenger = new Messenger(service);
        Message m = Message.obtain();
        m.replyTo = mClientMessenger;
        try {
            mServiceMessenger.send(m);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {}

    public class ClientHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            Log.d("Spam","Message Received");
        }
    }
}

RemoteService (メッセンジャーでテスト)

public class TestService extends Service {

    private Messenger mServiceMessenger = new Messenger(new ServiceHandler());
    private Messenger mClientMessenger;
    private Random r = new Random();

    public TestService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }


    @Override
    public IBinder onBind(Intent intent) {
        return mServiceMessenger.getBinder();
    }

    public void initSpam(){
        for(int i=0;i<10;i++) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    Bundle b = new Bundle();
                    b.putInt("INT",r.nextInt());
                    b.putLong("LONG",r.nextLong());
                    b.putBoolean("BOOL",r.nextBoolean());
                    b.putFloat("FLOAT",r.nextFloat());
                    b.putDouble("DOUBLE",r.nextDouble());
                    b.putString("STRING",String.valueOf(r.nextInt()));
                    Message msg = Message.obtain();
                    msg.setData(b);

                    try {
                        mClientMessenger.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            };
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(task,1,1);
        }
    }

    public class ServiceHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            mClientMessenger = msg.replyTo;
            initBarrage();

        }
    }
}

2 回目の試みは AIDL で行われました。これは IPC 用のバインダーも実装しますが、オーバーヘッドが大幅に少ないと想定しました。ただし、AIDL はメッセンジャーよりも大幅に効率的であるとは言えず、吃音の問題も解決しませんでした。

MainActivity (AIDL でテスト)

public class MainActivity extends Activity implements ServiceConnection{

    IRemoteService mService;
    TextView countTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this,TestService.class);
        bindService(intent,this, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {

        mService = IRemoteService.Stub.asInterface(service);
        try {
            mService.registerCallback(mClientBinder);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {}


    public final IServiceAidlCallback.Stub mClientBinder = new IServiceAidlCallback.Stub(){
        public void basicTypes(int anInt, long aLong, boolean aBoolean,
                               float aFloat, double aDouble, String aString){
            Log.d("Spam","Callback Received");
        }
    };
}

RemoteService (AIDL でテスト)

public class TestService extends Service {

    private Random r = new Random();

    private IServiceAidlCallback mClientCallback;

    public TestService() {
        super();
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public final IRemoteService.Stub mBinder = new IRemoteService.Stub(){
        public void registerCallback(IBinder callback){

            mClientCallback = IServiceAidlCallback.Stub.asInterface(callback);
            initSpam();

        }
    };

    public void initSpam(){
        for(int i=0;i<10;i++) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    try {
                        mClientCallback.basicTypes(
                                r.nextInt(),
                                r.nextLong(),
                                r.nextBoolean(),
                                r.nextFloat(),
                                r.nextDouble(),
                                String.valueOf(r.nextInt()));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            };
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(task,1,1);
        }
    }
}

これらのケースのいずれかで、私が〜5,000/秒を超えるのを妨げる何か間違ったことをしていますか? または、私が知らなかった Android IPC 用の別のシステムはありますか?

4

1 に答える 1

4

そのようなことをしてください:

主な活動

// use it for writing: stream.write(byte[]) 
// (make sure to write as biggest data chunks as possible)
// or wrap it around some other streams like DataOutputStream
private OutputStream stream;

// ServiceConnection implementation
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
    try {
        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
        stream = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);

        Parcel data = Parcel.obtain();
        FileDescriptor readFileDescriptor = pipe[0].getFileDescriptor();
        data.writeFileDescriptor(readFileDescriptor);
        service.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0);
    } catch (Exception e) {
        e.printStackTrace();
    }
    Log.d(TAG, "onServiceConnected " + stream);
}

リモートサービス

@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind ");
    return binder;
}

IBinder binder = new Binder() {
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        ParcelFileDescriptor pfd = data.readFileDescriptor();
        final InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
        // do something with a 'stream', start a new Thread for example and read data in a loop
        ...
        ...
        return true;
    }
};
于 2015-11-13T08:49:38.903 に答える