一、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);