Android -- Service绑定解绑和aidl
Service是安卓四大组件之一,先前讲到了Service的生命周期,以及非绑定类型的生命周期的例子,这次来分享一下绑定形式的。
应用组件(客户端)可以调用bindService()绑定到一个service。Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder。
绑定是异步的,bindService()会立即返回,它不会返回IBinder给客户端。要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService()。ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder。
-
实现ServiceConnection
实现必须重写两个回调方法:
onServiceConnected()
系统调用这个来传送在service的onBind()中返回的IBinder。
OnServiceDisconnected()
Android系统在同service的连接意外丢失时调用这个.比如当service崩溃了或被强杀了.当客户端解除绑定时,这个方法不会被调用。
-
调用bindService(),传给它ServiceConnection的实现。
-
当系统调用你的onServiceConnected()方法时,你就可以使用接口定义的方法们开始调用service了。
-
要与service断开连接,调用unbindService()。
-
程序
public class MainActivity extends Activity { private Button btn_start; private Button btn_stop; private Button btn_change; private Button btn_bind; private Button btn_unbind; private MyConn myConn; private IService myBinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_start = (Button) findViewById(R.id.btn_start); btn_stop = (Button) findViewById(R.id.btn_stop); btn_change = (Button) findViewById(R.id.btn_change); btn_bind = (Button) findViewById(R.id.btn_bind); btn_unbind = (Button) findViewById(R.id.btn_unbind); buttonListener bl = new buttonListener(); btn_change.setOnClickListener(bl); btn_start.setOnClickListener(bl); btn_stop.setOnClickListener(bl); btn_bind.setOnClickListener(bl); btn_unbind.setOnClickListener(bl); } class buttonListener implements OnClickListener { @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start: Intent intent_start = new Intent(getApplicationContext(),BindService.class); startService(intent_start); break; case R.id.btn_stop: Intent intent_stop = new Intent(getApplicationContext(),BindService.class); stopService(intent_stop); break; case R.id.btn_change: if(myBinder != null) myBinder.doChange("啦啦啦"); break; case R.id.btn_bind: if(myConn == null) { myConn = new MyConn(); Intent intent_bind = new Intent(getApplicationContext(),BindService.class); bindService(intent_bind, myConn, BIND_AUTO_CREATE); } break; case R.id.btn_unbind: Intent intent_unbind = new Intent(getApplicationContext(),BindService.class); if(myConn != null && myBinder != null) { unbindService(myConn); myConn = null; myBinder = null; } break; default: break; } } } private class MyConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { System.out.println("代理人返回回来了,onServiceConnected"); myBinder = (IService) service; } @Override public void onServiceDisconnected(ComponentName name) { System.out.println("接触绑定了,onServiceDisconnected"); } } }
Service类:
public class BindService extends Service { @Override public IBinder onBind(Intent intent) { System.out.println("Service绑定成功,onBind"); //返回自定义的代理对象 return new MyBinder();//这里的返回是返回到MainActivity里面的绑定myConn } @Override public boolean onUnbind(Intent intent) { System.out.println("Service解绑成功,onUnbind"); return super.onUnbind(intent); } public class MyBinder extends Binder implements IService { //间接的利用代理人调用了changeServiceThing的方法 public void doChange(String what) { changeServiceThing(what); } } @Override public void onCreate() { System.out.println("Service开启,onCreate"); super.onCreate(); } @Override public void onDestroy() { System.out.println("Service关闭,onDestroy"); super.onDestroy(); } public void changeServiceThing(String what) { Toast.makeText(getApplicationContext(), what+"变换了,changeServiceThing", Toast.LENGTH_LONG).show(); } }
IService:
public interface IService { public void doChange(String what); }
结果
点击“开启服务”之后,再“绑定服务”,这样执行之后直接点“关闭服务”是没用的,要先“解除服务”,再“关闭服务”。如果直接“绑定服务”,那么点击“关闭服务”没有用,需要点击“解绑服务”。
aidl
进程间通信->调用者和Service如果不在一个进程内,就需要使用android中的远程Service调用机制。
android使用AIDL定义进程间的通信接口。AIDL的语法与java接口类似,需要注意以下几点:
- AIDL文件必须以.aidl作为后缀名。
- AIDL接口中用到的数据类型, 除了基本类型, String, List, Map, CharSequence之外, 其他类型都需要导包, 即使两种在同一个包内. List和Map中的元素类型必须是AIDL支持的类型。
- 接口名需要和文件名相同。
- 方法的参数或返回值是自定义类型时, 该自定义的类型必须实现了Parcelable接口。
- 所有非java基本类型参数都需要加上in, out, inout标记, 以表明参数是输入参数, 输出参数, 还是输入输出参数。
- 接口和方法前不能使用访问修饰符和static, final等修饰。
进程间通信需要创建aidl文件,IService.aidl:
public interface IService { public void doChange(String what); }
接口中有一个static的抽象内部类Stub,Stub类继承了Binder类并实现了IRemoteService接口。
public class MainActivity extends Activity { private Intent intent; private IService iService; private ServiceConnection myConn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void bind(View view) { intent = new Intent(); intent.setAction("com.yydcdut.alipay"); myConn = new MyConn(); boolean flag = bindService(intent, myConn, BIND_AUTO_CREATE); System.out.println("flag------>" + flag); } private class MyConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { iService = IService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } } public void method(View view) { try { iService.callMethodInService(); } catch (RemoteException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }
在实现这个的时候我建立了两个程序,这样可以做到进程间通信。附带了源码。
我是天王盖地虎的分割线
源代码:http://pan.baidu.com/s/1dD1Qx01
service学习2.zip
aidl学习.zip
aidl学习配套2.zip
转载请注明出处:http://www.cnblogs.com/yydcdut
出处:http://yydcdut.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。