具有Messenger或AIDL的快速IPC

问题描述 投票:6回答:2

我正在尝试在Android中创建一个与远程服务快速通信的程序(〜40,000 / sec),但是所有Android IPC似乎都无法完成此任务。我的第一个尝试是使用标准Messenger系统,该系统无法以约2000 /秒的速度运行,同样糟糕的是,它似乎间歇性地出现了点差。

MainActivity(对Messenger进行测试)

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(对Messenger进行测试)

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();

        }
    }
}

第二次尝试是使用AIDL完成的。尽管这也实现了IPC绑定程序,但我认为开销要少得多。但是,事实证明,AIDL的效率不比Messengers高得多,并且它也无法解决口吃问题。

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系统?

android performance android-service ipc android-binder
2个回答
4
投票

做类似的事情:

MainActivity

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

RemoteService

@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;
    }
};

0
投票

@@ pskink这是我的代码。一旦您阅读,我就会删除它。

我的目标是将在同一应用中运行但以两个不同过程运行的两个活动进行交互。我有一类叫做MainActivity和DirectoryExplorer ...

class MainActivity extends Activity { ... }
class DirectoryExplorer extends Activity { ... }

DirectoryExplorer处于其自身的过程中,因为它与MainActivity处于同一任务中,并且如果死亡,MainActivity将不会被Android重新生成。

MainActivity启动DirectoryExplorer以便导入文件...

class MainActivity extends Activity
                                  implements GlobalConstants
{
     @Override public boolean onOptionsItemSelected(MenuItem item)
     {
         switch(item.getItemId())
         {
           case R.id.import: 
              DirectoryExplorer.show(this, IMPORT, new BinderParcelable(this));
              return true;
         }
     }
}

class DirectoryExplorer extends Activity
                                  implements GlobalConstants
{
     IBinder binder ;

     public static void show(MainActivity activity,String action,IBinder binder)
    {
     Intent intent = new Intent(activity,DirectoryExplorer.class);
     intent.setAction(action);
    if(binder != null) intent.putExtra("binder",new BinderParcelable(binder));
    if(action == EXPORT) intent.putExtra("content_path",activity.content.getDataFile());
    activity.startActivity(intent);
   }

    @Override protected void onCreate(Bundle state)
    {
      super.onCreate(state);
      binder = ((BinderParcelable)getIntent().getParcelableExtra("binder")).binder;
    }

// This is where I test the binder
// commented out code are alternatives I tried
final void onConfirm()
{
    Parcel data = Parcel.obtain(); data.writeInt(1000);
    Parcel reply = Parcel.obtain();

    switch(getIntent().getAction())
    {
        case "IMPORT":    try{ "transact result : " + binder.transact(ON_FINISH_IMPORT,Parcel.obtain(),null,0); }
                       catch(RemoteException e){ }

      .               // This simply works. But I want to use raw Binder
                      // Message msg = Message.obtain();
                      // try{messenger.send(msg);}
                       //catch(RemoteException e){ }

                      // This fails
                       //try{ dirExplInterface.print("Interface working"); }
                       //catch(RemoteException e) { }
                    break;
       }

       data.recycle();
       reply.recycle();
   }
}

class BinderParcelable implements Parcelable
{
  IBinder binder;

 ...a
}   
© www.soinside.com 2019 - 2024. All rights reserved.