Android中的四大组件之Service详解

时间:2022-12-21 12:10:13
Android中的四大组件之Service详解
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..");
}
}
}


(2)创建MainActivity.java

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;
interface MyAIDLService {
int plus(int a, int b);
String toUpperCase(String str);
}
   点击保存之后会在gen目录下生成一个MyAIDLService.java文件。

 (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文件。