前一篇我们分析了service的一些基本知识和用法,service全面解析(一),今天一起来看看如何提高service的进程优先级,跨进程通信的问题。
一:如何将service设置为前台进程:
首先我们简单的来看下Android中的几种进程:
1.前台进程(active process)
前台进程是那种用于和用户交互控件的程序,这些进程Android系统都会极力保护的,一般以下的场景都是前台进程:
a:处于前台的activity,它用于和用户进程交互
b:activity service 或者正在执行onReceiver()方法的BroadcastReceiver
c:正在执行onStart onCreate onDestroy方法的service
2.可见进程(Visible Process)
可见但不活动的那些进程,一般是可见的Activity但是不能和用户进行交互,比如一个Activity被部分遮挡的时候,可见进程在极端的情况下才会被系统杀死,来维护前台进程,一般的可见进程有
a:可见的Activity,但是处于onPause状态
b.被绑定到可见Activity的service
3.服务进程(service process)
进程中已经启动的service,
4.后台进程(background process)
不可见的Activity和没有启动的service都属于后台进程
5.空进程(empty process)
Android中问了整个系统性能,会保留把些已经走完生命周期的应用程序,Android缓存这些进程用来提高再次启动应用的时间。
分析完Android中的进程,我们会发现service处于第三个服务进程中,通常我们会将一个耗时的操作放在一个线程中,见这样的线程放在service中比放在Activity中会有较高的优先级,降级被系统杀掉的可能性,因为Activity一旦被转为后台,它的优先级会降为第四级的后台进程,明显没有service的进程优先级高。
service中有两个方法用来设置为前台进程和取消前台进程
startForeground(int id,Notification notif)可以设置services为前台进程;
stopForeground(int id)取消前台进程
将service设置为前台进程
Intent intent = new Intent();
intent.setClass(this, ServiceActivity.class);//设置目标service
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification(R.drawable.weixin,
"service", System.currentTimeMillis());
notification.flags = Notification.FLAG_ONGOING_EVENT;
notification.setLatestEventInfo(this, "service",
"serviceForeprocess",
pendingIntent);
startForeground(2525, notification);
这样我们就可很容易讲一个service设置为前台进程,被设置为前台的service拥有最高的优先级,这样我们可以降级被系统杀掉的风险。
一:service跨进程通讯
有的时候我们需要跨进程去和另一个应用进程通讯,Android跨进程通讯有好几种比如broadcastReceiver等还有我们今天要讲的service跨进程调用
service的跨进程调用称为AIDL(Android Interface Define Language)Android接口定义语言。AIDL相当于两个进程通讯的协议,按照这个协议编写程序就可以进程进程通讯。
进程通讯需要两个应用程序,首先我们来看看服务端的代码。我们创建一个服务端应用起名为AndroidTestAidl,接着创建一个包为com.sg.androidtestaidl,在这包下我们创建一个AIDL文件IMyService.aidl
interface IMyService {
void play(String taregetStr);
}
这里需要注意的是在定义aidl文件的时候,不能有访问修饰符就算是public也不行,出了基本类型 String List Map 其他的都需要导包,就算是在同一个包下也需要导包。
好了创建好IMyService.aidl文件之后刷新一下我们的工程,会在gen目录下生成对应的接口文件IMyService.java,打开这个文件我们简单看一下。
我们看第九行Stub是IMyService类的内部抽象类继承了Binder类 这个是需要我们之后在绑定service的时候返回的,再看21行Stub的asInterface方法,这个方法负责将客户端返回的对象转为IMyService.Stub对象 我们在看90行就是我们在在aidl文件中声明的方法。
接下来看看我们的AIDLService.Java
public class AIDLService extends Service {
public static String TAG = AIDLService.class.getSimpleName();
public MyBinder binder;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.i("---------", "-----------aidlonbind-------");
return new MyBinder();
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("---------", "-----------onStartCommand-------");
return super.onStartCommand(intent, flags, startId);
}
public class MyBinder extends IMyService.Stub {
@Override
public void play(String targetStr) throws RemoteException{
AIDLService.this.play(targetStr);
}
}
public void play(String targetStr) {
Log.i(TAG, "---------" + targetStr);
}
}
我们在AIDLService 类中定义了一个MyBinder类,它继承IMyService.Stub,这里和定义本地service通信不同,并在onBind方法中返回这个对象,在play方法中打印了一下传进来参数。
最后注册一下service
<service android:name=".AIDLService" >
<intent-filter>
<action android:name="com.example.service.aidl" />
</intent-filter>
</service>
最后在创建一个客户端程序,将IMyService.aidl连通包一起复制到我们的客户端应用中。因为AIDL文件两个应用的包名文件必须一致。看看客户端调用服务端的代码:
public class ServiceActivity extends Activity implements OnClickListener {
private IMyService binder;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.service_main);
Button start_service_bt = (Button) findViewById(R.id.bt_start_service);
Button stop_service_bt = (Button) findViewById(R.id.bt_stop_service);
Button bind_service_bt = (Button) findViewById(R.id.bt_bind_service);
start_service_bt.setOnClickListener(this);
stop_service_bt.setOnClickListener(this);
bind_service_bt.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.example.service.aidl");
switch (v.getId()) {
case R.id.bt_start_service:
try {
binder.play("service跨进程通讯");;
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.bt_stop_service:
unbindService(connection);
break;
case R.id.bt_bind_service:
bindService(intent,connection,Service.BIND_AUTO_CREATE);
break;
}}
private ServiceConnection connection = new ServiceConnection({
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.i("---------", "-------disConnection-------");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = IMyService.Stub.asInterface(service);
}
};
}