最近有用到Activity需要不断的从Service中获取数据,第一个想法肯定就是通过bind回调机制了,有几点概念模糊特此记录下:
单独使用bindService(),unbindService()会经历:->onCreate()->onBind()->Service running->onUnbind() -> onDestroy() 。
单独使用startService(),stopService()会经历:->onCreate()->onStartCommand()->Service running-> onDestroy() 。
先调用startService(),再调用bindService()方法:
4、关于停止Service,如果service是非绑定的,最终当任务完成时,为了节省系统资源,一定要停止service,可以通过stopSelf()来停止,也可以在其他组件中通过stopService()来停止,绑定的service可以通过onUnBind()来停止service。
关于Activity与Service数据的互相传递,写了个demo:
public class MainActivity extends Activity implements View.OnClickListener { private TextView mTextView; private EditText mEditText; private MyService.LocalBinder binder=null; MyService myService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEditText = (EditText) findViewById(R.id.edt_content); Button mBtnStart = (Button) findViewById(R.id.btn_start); Button mBtnClose = (Button) findViewById(R.id.btn_close); Button mBtnSubmit = (Button) findViewById(R.id.btn_submit); mTextView = (TextView) findViewById(R.id.tv_show); mBtnStart.setOnClickListener(this); mBtnClose.setOnClickListener(this); mBtnSubmit.setOnClickListener(this); } public ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { binder = (MyService.LocalBinder) service;//得到LocalBinder实例 myService = binder.getService();//得到Service实例 //设置接口回调获取Service中的数据 myService.setOnDataCallback(new MyService.OnDataCallback() { @Override public void onDataChange( final String message) { runOnUiThread(new Runnable() { @Override public void run() { mTextView.setText(message); } }); } }); } @Override public void onServiceDisconnected(ComponentName name) { myService = null; } }; @Override public void onClick(View v) { Intent intent = new Intent(this,MyService.class); switch (v.getId()){ case R.id.btn_start: // startService(intent); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);//为Activity绑定服务 break; case R.id.btn_close: unbindService(mServiceConnection);//解除绑定 // stopService(intent); break; case R.id.btn_submit: if(binder!=null){ //把数据传给Service,相比用Bundle效率更高 binder.setData(mEditText.getText().toString()); } break; } } @Override protected void onDestroy() { super.onDestroy(); unbindService(mServiceConnection);//解除绑定 } }MyService:
public class MyService extends Service { private String message ; private boolean isRunning = true; private IBinder binder = new LocalBinder(); public class LocalBinder extends Binder { public void setData(String message) { //从Activity传入message值 MyService.this.message = message; } public MyService getService() { //返回当前MyService对象 return MyService.this; } } private OnDataCallback mOnDataCallback=null; public void setOnDataCallback(OnDataCallback mOnDataCallback) { this.mOnDataCallback = mOnDataCallback; } public interface OnDataCallback{ void onDataChange(String message); } @Override public IBinder onBind(Intent intent) { //返回这个LocalBinder对象,其实这个对象可以在Activity中onServiceConnected()方法中接收到,这个bind就是Activity和Service通信的桥梁 //因为在Activity通过这个bind对象可以得到Service的实例引用。一旦Service对象找到,就能得到它的公共方法和属性。 return binder; } @Override public void onCreate() { super.onCreate(); new Thread() { @Override public void run() { int i=1; while (isRunning) { if(mOnDataCallback!=null){ mOnDataCallback.onDataChange(message + i); } i++; try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); isRunning = false; } }Activity能进行绑定得益于Service的接口onBind()。Service和Activity的连接可以用ServiceConnection来实现,需要实现一个新的ServiceConnection,重写onServiceConnected和onServiceDisconnected方法。执行绑定,调用bindService方法,传入一个选择了要绑定的Service的Intent(显式或隐式)和一个你实现了的ServiceConnection实例。一旦连接建立,你就能通Service的接口onBind()得到mBinder实例进而得到Service的实例引用。一旦Service对象找到,就能得到它的公共方法和属性。但这种方式,只能在同一个进程和同一个Application里。跨进程跨应用通信IPC需要建立aidl文件(注:Android5.0以后跨应用只能通过显示Intent来启动Service,即包名、类名)。