1.Service的生命周期
(1)通过调用startService() onCreate->onStartCommand()->onDestory();注意:onCreate()方法只会在第一次开启服务时被调用。
(2)通过调用bindService() onCreate->onBind()->onUnbind()->onDestory()
2.Service和Activity之间的通信
(1)创建MyService.java
public class MyService extends Service {
public static String TAG = "MyService";
@Override
public void onCreate() {
Log.d(TAG,"onCreate...");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand...");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent arg0) {
Log.d(TAG,"onBind...");
return new MyBind();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind...");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.d(TAG,"onDestory...");
super.onDestroy();
}
class MyBind extends Binder{
public void startDownload(){
Log.d(TAG,"startDownload..");
}
}
}
public class MainActivity extends Activity implements OnClickListener{
private Button startButton;
private Button stopserButton;
private Button bindButton;
private Button unBindButton;
private MyService.MyBind myBind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton =(Button) findViewById(R.id.startService);
stopserButton = (Button) findViewById(R.id.stopService);
bindButton = (Button) findViewById(R.id.bindService);
unBindButton = (Button) findViewById(R.id.unBindSer);
bindButton.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bindService:
Intent service = new Intent(this,MyService.class);
//第三个参数表示建立连接后自动创建service,其中onCreate会被调用。
bindService(service, connection, Context.BIND_AUTO_CREATE);
break;
default:
break;
}
}
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBind = (MyBind) service;
myBind.startDownload();
}
};
}
3.销毁Service
(1)通过startService()启动Service时只要通过stopService()就可以关闭Service。
(2)通过bindService()启动Service时只要通过unbindService()可以关闭Service。
(3)如果先startService(),然后又bindService(),这个时候就必须调用stopService()和unbindService()才会关闭Service。也就是说stopService()只会让Service停止,还需要解除Service与Activity之间的关联,Service才会被销毁。
4.创建前台Service
由于Service在系统中的优先级比较低,所以可能会在系统内存不足的时候被会回收掉。那么怎么保证Service在内存不足时也不会被回收掉呢?可以考虑使用前台Service。前台Service与普通Service最大区别就是会在系统通知栏显示。
我们来创建一个前台Service MyForgroundService.java,其实非常简单。
public class MyForgroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
Notification notification = new Notification(R.drawable.ic_launcher, "福利来啦!", System.currentTimeMillis());
Intent intent = new Intent(this,MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
notification.setLatestEventInfo(this, "通知标题", "通知内容", contentIntent);
startForeground(1, notification);
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
5.IPC(Inter-Process Communication,进程间通信)
AIDL(Android Interface Definition Language)是Android接口定义语言的意思,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。
实现Activity与远程服务的通信主要是下面三个步骤:
(1)新建一个aidl接口文件,顾名思义,这个文件主要描述的是客户端所需要调用的方法。
新建MyAIDLService.aidl文件,这里主要给客户端提供两个方法,分别是加法运算以及字符串转大写。代码如下所示:
package com.example.servicetest;点击保存之后会在gen目录下生成一个MyAIDLService.java文件。
interface MyAIDLService {
int plus(int a, int b);
String toUpperCase(String str);
}
(2)在服务端实现需要被客户端调用的方法,并在onBind()中返回bind对象。
public class MyService extends Service {
......
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//Stub就是Binder的子类
MyAIDLService.Stub mBinder = new Stub() {
@Override
public String toUpperCase(String str) throws RemoteException {
if (str != null) {
return str.toUpperCase();
}
return null;
}
@Override
public int plus(int a, int b) throws RemoteException {
return a + b;
}
};
}
注意:这里的Service需要在清单文件中注册,而且还需要添加一个action,因为客户端和服务器不在同一个应用中了,那么启动Service时就必须使用隐式Intent了。
(3)将服务器端自动生成的MyAIDLService.java拷贝到客户端项目目录下。然后在客户端通过bindService()获得服务端的bind对象,通过bind对象调用Service端的方法。
public class MainActivity extends Activity implements OnClickListener {
private Button startService;
private MyAIDLService myAIDLService;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取bind对象
myAIDLService = MyAIDLService.Stub.asInterface(service);
try {
int result = myAIDLService.plus(3, 5);
String upperStr = myAIDLService.toUpperCase("hello world");
Log.d("TAG", "result is " + result);
Log.d("TAG", "upperStr is " + upperStr);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
......
}
6.两种方式开启Service的区别?
当选择startService时,这样开启一个服务后,这个服务就与调用者没有关系了,也就是说如果调用者不存在了,Service也是可以正常存在的,如果需要关闭Service,则必须调用stopService去停止Service。
当选择bindService时,这样开启的服务于调用者是绑定在一起的,也就是说如果调用者被杀死了,这个服务也会被关闭。如果需要关闭一个正常运行的Service可以调用unbind去解除绑定。
7.最后要说明一点的就是,由于这是在不同进程之间传递数据,因此Android对这类数据格式支持是非常有限的,比如java基本数据类型,字符串,List,Map等。那么怎么传递一个自定义的类呢?这个时候可以使用序列化,即实现Serializable或者Parcelable。
并且要给这个类也定义一个同名的AIDL文件。