内容是安卓中跨应用的服务与界面的相互通信。
首先是文件结构,如下图,分别创建两个APP,app(service)和remoteApp(client),App只负责服务部分,remoteApp用于显示服务回传的数据和修改服务的数据的功能。现在需要跨应用通信的app中创建AIDL文件,分别为ITaskBinder.aidl和ITaskCallback.aidl,ITaskCallback,ITaskBinder用于编写提供给client回调用的接口,ITaskCallback用于编写注册callback的方法。
ITaskCallback.aidl代码
// ITaskBinder.aidl //注意修改包名 package ***.***.learnservice; import ***.***.learnservice.ITaskCallback; interface ITaskBinder { void registerCallback(ITaskCallback cb); //用于注册callback void unregisterCallback(ITaskCallback cb);//用于解除callback的注册 void setServicePrint(String str); }
ITaskBinder.aidl代码
// ITaskCallback.aidl //注意修改包名 package ***.***.learnservice; interface ITaskCallback { void sendString(String str); //向client回传字符串数据 }
下面来讲讲service中需要实现的内容
MyService.java代码
package ***.***.learnservice; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; public class MyService extends Service { private boolean running=false; private String outStr="服务运行中..."; private boolean reg=false; public MyService() { } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); running=true; System.out.println("服务启动"); } @Override public void onDestroy() { super.onDestroy(); running=false; System.out.println("服务销毁"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(){ @Override public void run() { super.run(); int i=0; while (running) { String str=i+":"+outStr; System.out.println(str); if(reg){ callback(str);//条件符合就回传数据 } i++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); return super.onStartCommand(intent, flags, startId); } void callback(String str) { final int N = mCallbacks.beginBroadcast(); System.out.println(N); for (int i=0; i<N; i++) { try { mCallbacks.getBroadcastItem(i).sendString(str); } catch (RemoteException e) { } } mCallbacks.finishBroadcast(); } private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() { public void registerCallback(ITaskCallback cb) { if (cb != null) { mCallbacks.register(cb); reg=true; } } public void unregisterCallback(ITaskCallback cb) { if(cb != null) { mCallbacks.unregister(cb); reg=false; } } @Override public void setServicePrint(String str) throws RemoteException { MyService.this.outStr=str; } }; final RemoteCallbackList<ITaskCallback> mCallbacks = new RemoteCallbackList <ITaskCallback>(); }
先来看 final RemoteCallbackList<ITaskCallback> mCallbacks = new RemoteCallbackList <ITaskCallback>();
快应用的通信时通过RemoteCallbackList来实现的,用一个RemoteCallbackList来存储callback的列表。
首先我们需要实现一个ITaskBinder.Stub,用于注册和接触注册,或者是更改服务里面的内容的IBinder实例,我们需要在onBind()中返回它给client。
然后编写一回调函数void callback(String str),在callback里面,先通过mCallbacks.beginBroadcast();来获取当前的数目(这里应该指的是注册了的回调函数的数目,不过我没有测试过),然后通过mCallbacks.getBroadcastItem(i).sendString(str);
向client发送数据,sendString(str);就是你之前在ITaskBinder.aidl中实现的接口。
下面来看removeApp的内容
MainActivity.java代码
//注意根据你的包名来更改 package ***.***.remoteapp; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.TextView; //注意根据你的包名来更改 import ***.***.learnservice.ITaskBinder; import ***.***.learnservice.ITaskCallback; public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection { private TextView tv; private EditText et; private Intent anotherAppServiceIntent=new Intent(); private static String backStr=""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //注意根据你的包名来更改 anotherAppServiceIntent.setComponent(new ComponentName("***.***.learnservice","***.***.learnservice.MyService")); tv= (TextView) findViewById(R.id.tv); et= (EditText) findViewById(R.id.et); findViewById(R.id.startAnotherAppSercvice).setOnClickListener(this); findViewById(R.id.stopAnotherAppSercvice).setOnClickListener(this); findViewById(R.id.bindAnotherAppSercvice).setOnClickListener(this); findViewById(R.id.unbindAnotherAppSercvice).setOnClickListener(this); findViewById(R.id.changeAnothetAppService).setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.startAnotherAppSercvice: startService(anotherAppServiceIntent); break; case R.id.stopAnotherAppSercvice: stopService(anotherAppServiceIntent); break; case R.id.bindAnotherAppSercvice: bindService(anotherAppServiceIntent,this, Context.BIND_AUTO_CREATE); break; case R.id.unbindAnotherAppSercvice: binder=null; unbindService(this); break; case R.id.changeAnothetAppService: if(binder!=null) { try { binder.setServicePrint(et.getText().toString()); } catch (RemoteException e) { e.printStackTrace(); } } break; } } private ITaskBinder binder; ITaskCallback mCallback = new ITaskCallback.Stub() { @Override public void sendString(String str) throws RemoteException { Message message=new Message(); Bundle bundle=new Bundle(); bundle.putString("callbackString",str); message.setData(bundle); handler.sendMessage(message); } }; @Override public void onServiceConnected(ComponentName name, IBinder service) { System.out.println("绑定服务"); binder=ITaskBinder.Stub.asInterface(service); try { binder.registerCallback(mCallback); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { try { binder.unregisterCallback(mCallback); } catch (RemoteException e) { e.printStackTrace(); } System.out.println("解绑服务"); } Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); tv.setText(msg.getData().getString("callbackString")); } }; }
在client中,通过bindService绑定服务后,就可以在重写中的onServiceConnected方法中注册你写的callback函数, ITaskCallback mCallback = new ITaskCallback.Stub() {};
在mCallback里面通过复写sendString(String str)就可以获取到服务传过来的字符串数据了。由于安卓的安全机制,副线程不能更改当前的视图线程的资源,所以我们可以通过Handler来更新TextView中的内容。