一、Service
Service是一个在后台长期运行的应用组件,适用于IPC调用,当用于从当前app切换到别的app时service依然能跑在后台。当start一个service时,它马上跑起来,即使启动它的那个组件已经被销毁。如果bound一个service时,servcie是允许众多其他组件绑定它,只有当所有的client反绑定。unbind()之后才会destroy。
servcie可以像activity一样只允许当前的app使用,这需要在androidManifest.xml中声明。
*Caution: Service试运行在进程的主线程中(main thread),如果需要service去做一些高占用CPU或者堵塞的操作,那么应该新建线程去处理。
二、Service的分类
(1)LocalService
(2)RemoteService
三、如何添加并使用一个服务
(1)继承Service
(2)继承IntentService,
这是Service的一个子类。继承该类后,工作比较省事,只需要实现 onHandleIntent() 方法即可,且不用担心堵塞的问题,因为该类实现了多线程操作。如果要实现Service别的方法,那么一定要调用父类的方法。
四、start service 与 bind service是有区别的。
bind service可以获取一个返回的IBinder对象用于操作remoet service的方法。当不需要绑定服务时,unbindService().当其他的组件通过startService()启动服务时,系统会调用onStartCommand(),当service的工作结束时,程序员有责任去调用stopSelf()或者stopService(),但如果这个服务还提供绑定的话, 就不需要这么做。
当client调用bindService()时,系统会调用服务的onBind()方法,如果实现了该接口,那么应该返回一个IBinder变量给client用来通信。当服务第一次被创建时调用onCreate()。当服务不在被使用时,它会被销毁,因此系统调用onDestroy(),程序员应该在这里做一些资源与线程的释放工作。系统在低内存的时候,回去终止服务,如果这个服务被一个焦点的activity绑定,那么它被终止的肯能行会小很多,如果服务声明了运行在前台,那么它将不会被终止。
系统终止服务后,也会将一些服务重启,这个取决于onStartCommand()的值
五、终止service服务本身应该终止自己,推荐使用stopSelf(int),int值是onStartCommand()得到的startId,如果调用stopSelf(int)时,这个int值与startId不同,那么就不能销毁成功。因为每次bind服务的时候都会call onStartCommand(),而startId也不同。
如果是client的话,也需要有一个不使用服务的时候终止连接,stopService。
六、两个需要重视的方法
*public int onStartCommand (Intent intent, int flags, int startId)这是一个很重要的方法,当client调用startService的时候,系统会调用该方法。这个return的int值是给系统用的。比如return Service.START_STICKY;那么就是明确地告诉系统,如果不是主动stop这个service,那么是不想被系统终止的。
*public final void startForeground (int id, Notification notification)
这个方法可以让service处于前台且不被kill掉。
七、Service的生命周期图
\
八、Demo
(1) 实现一个aidl文件
*这时的gen里边会自动生成一个xxxservice文件
package com.bootoption;
import java.util.List;
interface IBootOptionService {
List getOriginalBlackList();
List getBlackList();
void setBlackList(in List list);
}
(2)实现Service
*,关键是要实现继承与aidl中stub的子类
package com.bootoption;
import java.util.List;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class BootOptionService extends Service {
static final String TAG = "bootOption";
private InnerObject innerBinder = new InnerObject();
class InnerObject extends IBootOptionService.Stub {
public List getOriginalBlackList() throws RemoteException {
Log.v(TAG, "getOriginalBlackList");
PackageManager pmg = BootOptionService.this.getPackageManager();
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
return pmg.queryBroadcastReceivers(intent, PackageManager.GET_RESOLVED_FILTER);
}
public List getBlackList() throws RemoteException {
Log.v(TAG, "getBlackList");
return null;
}
public void setBlackList(List list) throws RemoteException {
Log.v(TAG, "setBlackList");
}
}
@Override
public IBinder onBind(Intent arg0) {
Log.v(TAG, "onBind");
return innerBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
}
}
(3)本地调用
* 重点是实现
ServiceConnection
package com.bootoption;
import java.util.List;
import com.bootoption.IBootOptionService.Stub;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class BootOptionManagerActivity extends Activity {
static final String TAG = "bootOption";
private TextView tv = null;
private Button bt = null;
private IBootOptionService.Stub bos = null;
private ServiceConnection conn = new ServiceConnection() {
boolean bConnect = false;
public void onServiceConnected(ComponentName name, IBinder service) {
if (bConnect) {
bos = null;
}
bos = (IBootOptionService.Stub)service;
bConnect = true;
}
public void onServiceDisconnected(ComponentName name) {
if (bConnect) {
bos = null;
bConnect = false;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView)findViewById(R.id.text);
bt = (Button)findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
BootOptionManagerActivity.this.sendBroadcast(new Intent("android.intent.action.test"));
if (bos != null) {
try {
List list = bos.getOriginalBlackList();
Log.v(TAG, "bos is " + bos + ",list is " + list);
for (int i = 0; i < list.size(); i++) {
ResolveInfo ri = (ResolveInfo) list.get(i);
Log.v(TAG, "==> " + ri.toString());
PackageManager pm = BootOptionManagerActivity.this.getPackageManager();
try {
ApplicationInfo appInfo =
pm.getApplicationInfo(ri.activityInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
Log.v(TAG, "*" + appInfo.publicSourceDir);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Log.w(TAG, "bos is null");
}
}
});
Intent service = new Intent("android.intent.action.bootoption.service");
this.bindService(service, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onResume() {
super.onResume();
}
}
(4)远程调用
*将(1)中gen生成的xxxservice拿到远程调用的代码中
*注意包名
package com.my.app;
import com.bootoption.*;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class ACTActivity extends Activity {
static final String TAG = "RemoteService";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.bindService(new Intent("android.intent.action.bootoption.service"), sc, Context.BIND_AUTO_CREATE);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
Log.v(TAG, "configuration change");
}
IBootOptionService is = null;
ServiceConnection sc = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.v(TAG, "onServiceDisconnected");
is = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.v(TAG, "onServiceConnected");
//is = (IBootOptionService.Stub)service;
is = IBootOptionService.Stub.asInterface(service);
if (is != null) {
try {
is.setBlackList(null);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}
(5)总结,本地调用与远程调用的实现区别就在于:
*本地调用时,在onServiceConnected方法中是这样的:
private IBootOptionService.Stub bos = null;
......
bos = (IBootOptionService.Stub)service;
*远程调用时,在onServiceConnected方法中是这样的:
IBootOptionService is = null;
......
is = IBootOptionService.Stub.asInterface(service);