博客参照< < Android开发全程实录> >的例子 , 以及其他博客, 希望能给学习Android Service的小伙伴一个比较详细的解释与实践
Service的生命周期比Activity的简单, 只有3个:
其中 onCreate() 和 onDestroy() 只能被调用一次, onStart() 可以被调用多次. 使用start和bind两种方式启动Service的生命周期略有不同:
start方式: onCreate() -> onStartCommand() -> onStart() -> onDestroy()
bind方式: onCreate() -> onBind() -> onUnbind() -> onDestroy()
代码测试:
全套的生命周期Log:
public class MyService extends Service {
private final String TAG = this.getClass().getSimpleName();
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "onStart");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
}
}
别忘记注册service:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.xm.servicesimple">
<application>
...
<service android:name=".service.MyService" />
application>
manifest>
case R.id.btn_start_service:
Intent intent1 = new Intent(MainActivity.this, MyService.class);
startService(intent1);
break;
case R.id.btn_stop_service:
Intent intent2 = new Intent(MainActivity.this, MyService.class);
stopService(intent2);
break;
service第一次启动:
onCreate() -> onStartCommand() -> onStart()
再次启动:
onStartCommand() -> onStart()
关闭Service:
onDestroy()
再次onStart():
onCreate() -> onStartCommand() -> onStart()
如果通过bind方式, 除非调用过unbindService(), 否则service的生命周期和context相同, 在context被销毁时, service自动被销毁.
使用bind方法要复杂一点, 首先 需要一个 ServiceConnection对象, 当绑定时需要获得一个连接, 连接可以返回一个 IBinder接口, 可通过 IBinder接口获取 绑定Service的实例.
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private final String TAG = this.getClass().getSimpleName();
private Button mBtnStartServce;
private Button mBtnStopServce;
private Button mBtnBindServce;
private Button mBtnUnbindServce;
private Button mBtnDoSomeThing;
private boolean isBind;
private MyService mBindService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnStartServce = (Button) findViewById(R.id.btn_start_service);
mBtnStopServce = (Button) findViewById(R.id.btn_stop_service);
mBtnBindServce = (Button) findViewById(R.id.btn_bind_service);
mBtnUnbindServce = (Button) findViewById(R.id.btn_unbind_service);
mBtnDoSomeThing = (Button) findViewById(R.id.btn_do_something);
mBtnStartServce.setOnClickListener(this);
mBtnStopServce.setOnClickListener(this);
mBtnBindServce.setOnClickListener(this);
mBtnUnbindServce.setOnClickListener(this);
mBtnDoSomeThing.setOnClickListener(this);
isBind = false;
}
ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected:" + componentName.toString());
mBindService = ((MyService.MyBinder) iBinder).getService();
isBind = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected");
mBindService = null;
isBind = false;
}
};
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
switch (view.getId()) {
case R.id.btn_start_service:
startService(intent);
break;
case R.id.btn_stop_service:
stopService(intent);
break;
case R.id.btn_bind_service:
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
isBind = true;
break;
case R.id.btn_unbind_service:
if (isBind) {
unbindService(mServiceConnection);
isBind = false;
mBindService = null;
}
break;
case R.id.btn_do_something:
if(mBindService!=null){
mBindService.doSomeThing();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
MyService.java
public class MyService extends Service {
private final String TAG = this.getClass().getSimpleName();
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public void doSomeThing() {
Log.e(TAG, "doSomeThing");
}
public MyService() {
Log.e(TAG, "MyService");
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return new MyBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
}
}
service第一次启动:
onCreate() -> onBind() -> onServiceConnected()
继续点击bind:
无响应
点击 unbind:
onUnbind() -> onDestroy()
继续点击 unbind:
无响应
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
总之, AIDL是Android中通过Service获取统一接口, 进行进程间通信的的一种方法
写两个App, 一个作为Server端, 一个作为Client端. 在Server启动服务, 在Client端绑定Server端的服务, 并获取数据.
其实AIDL也是用bind方法绑定Service, 与前面不同的就是需要server端和cient端都定义统一的接口, 然后可以从client端得到server端的binder对象, 进而完成进程间通信.
Server端主要有3个文件修改:
package org.xm;
interface AIDLService {
String getServiceName();
}
创建Service文件
MyService.java
package org.xm.server;
public class MyService extends Service {
private static final String TAG = "MainActivity";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind");
return binder;
}
private AIDLService.Stub binder = new AIDLService.Stub() {
@Override
public String getServiceName() throws RemoteException {
return "ServiceName";
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
}
特别注意这里要返回的binder是 AIDLService.Stub对象, 而不是AIDLService对象.
然后我们在MainActivity启动时启动Service, 关闭时关闭Service:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
}
@Override
protected void onDestroy() {
Intent intent = new Intent(MainActivity.this, MyService.class);
stopService(intent);
super.onDestroy();
}
<service android:name=".MyService">
<intent-filter>
<action android:name="org.xm.AIDLService" />
intent-filter>
service>
注意: "org.xm.AIDLService"
最好是填写Service的名称, 后面bind的时候发送请求需要用到这里字段, 如果匹配上才能成功绑定.
到这里Server端就写完了.
Client端其实很简单了:
1. 定义和Server端相同的aidl接口
2. 执行基本的绑定步骤, 创建connection, 然后绑定 service
- AIDLService.aidl 与Server端的完全一致:
package org.xm;
interface AIDLService {
String getServiceName();
}
package org.xm.client;
//...
import org.xm.AIDLService;
public class MainActivity extends AppCompatActivity {
//...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//...
mBtnBindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("org.xm.AIDLService");
intent.setPackage("org.xm.server");
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
});
mBtnGetValue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mAidlService != null) {
try {
Log.e(TAG, "result:" + mAidlService.getServiceName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private AIDLService mAidlService = null;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "onServiceConnected");
mAidlService = AIDLService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mAidlService = null;
}
};
}
在绑定的代码中, 记得使用下面的方法:
Intent intent = new Intent("org.xm.AIDLService");
intent.setPackage("org.xm.server");
bindService(intent, mConnection, BIND_AUTO_CREATE);
Intent intent = new Intent(MainActiity.this, AIDLService.class);
//Intent intent = new Intent(MainActiity.this,AIDLService.Stub.class);
intent.setPackage("org.xm.server");
bindService(intent, mConnection, BIND_AUTO_CREATE);
Service Intent must be explicit: Intent ....
错误一定要使用 intent.setPackage("org.xm.server");