Service是一种长生命周期的组件,是一个没有界面的Activity,它是Activity的叔叔。
java
·Service长期在后台运行,用来访问网络、播放音乐、操做文件或与内容提供者交互等无关界面的操做。android
·Service和Thread相似,可是Thread不安全也不严谨。程序员
·Service是运行在主线程中,所以不能用来作耗时的操做。api
进程优先级由高到低的顺序:
缓存
·前台进程(Foreground progress)安全
·可视进程(Visible process),能够看见,可是不能够交互。网络
·服务进程(Service process)异步
·后台进程(Background process)ide
·空进程(Empty process)当程序退出时,进程没有被销毁,而是变成了空进程函数
Android系统有一套内存回收机制,会根据优先级进行回收。Android系统会尽量的维持程序的进程, 可是终究仍是须要回收一些旧的进程节省内存提供给新的或者重要的进程使用。
· 进程的回收顺序是:从低到高
· 当系统内存不够用时, 会把空进程一个一个回收掉
· 当系统回收全部的完空进程不够用时, 继续向上回收后台进程, 依次类推
· 可是当回收服务, 可视, 前台这三种进程时, 系统非必要状况下不会轻易回收, 若是须要回收掉这三种进程, 那么在系统内存够用时, 会再给从新启动进程;可是服务进程若是
用户手动的关闭服务, 这时服务不会再重启了
标准方式开启服务,服务会执行onCreate方法,若是服务已经被建立,就不会再去执行onCreate方法。屡次的开启服务会执行onStartCommand()方法,它替代了过期的onStart()方法。
中止服务,服务会执行ondestry()方法。
1.标准模式
Intent intent = new Intent(MainActivity.this,PhoneServer.class); startService(intent);
Activity经过标准模式开启的服务长期在后台运行,不能够调用服务里的方法。
oncreate() -->onstartCommand()--->onstartCommand()--->onDestory();
2.绑定模式
Intent intent = new Intent(MainActivity.this, PhoneService.class); /** * service:intent * conn 服务的通信频道 * 服务若是在绑定的时候不存在,会自动建立 * */ bindService(intent, new MyConn(), BIND_AUTO_CREATE);
Activity经过绑定模式开启的服务能够调用服务的方法,可是不能长期运行在后台。
onCreate()-->onbind()-->onUnbind()-->ondestroy();
·若是obind方法返回值是null,onServerConnected方法不会被调用。
·绑定的服务在系统设置界面,正在运行条目是看不到的。
·绑定的服务和Activity不求同时生,但求同时死。
·解除绑定服务后,服务会当即中止,且服务只能够被解除绑定一次,屡次解除绑定代码会抛出异常。
3.混合模式
Activity经过混合模式开启服务便可以长期在后台运行,也能够调用服务中的方法。
·首先经过标准模式启动服务,这样服务就长期在后台运行。
·若是须要调用服务中的方法,则再使用绑定模式绑定服务。
·若是须要解绑服务则调用unbindService()解绑服务。
·若是须要中止服务,则调用stopService()中止服务。
注:有时候咱们解绑服务后,发现仍是能够调用服务中的方法,是由于垃圾回收器尚未回收调用该方法的对象。
由上面能够知道,Activity只有绑定模式开启服务才能调用服务中的方法,别忘记解绑服务:
咱们须要在服务中建立一个类,继承iBinder的子类Binder,来充当咱们的代理类
除此以外,还可使用接口解耦,建立一个接口充当代理类的父类,让定义的代理类实现该接口中的方法再调用服务中的方法,而后在onBind中返回代理类,
在MainActivity中的再进行强制类型转换,和以上实现方法同样。
aidl()Android Interface definition language),它是一种android内部进程通讯接口的描述语言,经过它咱们能够定义进程间的通讯接口
IPC(interprocess communication)内部进程通讯,知足两个进程之间接口数据的交换。
1.使用方法
a) .java的接口文件后缀修改为.aidl文件,并删除piblic访问修饰符。
b) 在工程目录gen目录下会自动编译成Iservice.java的接口文件。
c) 远程服务代码
private class MyBinder extends IService.Stub
d) 本地服务代码
IService = IService.Stub.asInterface(setvice)
e)IService.callMethodInService()
这里很少讲述,在后面的IPC机制讲解时进行详细说明。
一、简介
IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工做线程来处理耗时操做,启动IntentService的方式和启动传统Service同样
,同时,当任务执行完后,
IntentService会自动中止,另外,能够启动IntentService屡次,而每个耗时操做会以工做队列的方式在IntentService的onHandleIntent回调方法中执行,
而且,每次只会执行一个工做线程,
执行完第一个再执行第二个,以此类推。并且,全部请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。
二、使用
服务是运行在主线程的,咱们不能在服务中作耗时操做,而IntentService却恰好是用来解决该问题的,固然在服务中作耗时操做有两种,
第一种直接开启线程,第二种则是用IntentService。
@Override protected void onHandleIntent(Intent intent) { // Intent是从Actvity发过来的,携带识别参数,根据参数不一样执行不一样人物 String action = intent.getExtras().getString("param"); if(action.equals("oper1")){ System.out.println("Operation1"); }else if (action.equals("oper2")) { System.out.println("Operation2"); } SystemClock.sleep(2000); }
onHandleIntent方法就是专门用来处理耗时操做的。
1.反射挂断电话
a)找到上下文的mBase引用的类,ContextImpl,经过查看getSystemService源码能够知道,全部的系统服务都在一个map集合中。
b)接下来去查找map集合SYSTEM_SERVERCE_MAP,发现它实际上是一个hashMap,这里须要详细解说:
为何谷歌须要包装上下文?假设在没有上下文的状况下,想要调一个服务,首先要绑定该服务,若是成功绑定会返回IBinder,拿到IBinder后还须要将它转化成为接口类型,
才能去调用它的函数,因此谷歌在设计的时候将经常使用的上下文都包装好了,这样对程序员开发更加的方便,快捷。
因为某些服务被认为不安全或侵犯用户隐私,因此谷歌在包装系统服务的时候,将某些服务进行了隐藏(@hide),好比挂断电话。
咱们须要先拿到ServiceManager对象, 可是谷歌不但愿咱们使用该对象,因此将该对象进行隐藏,因此参考下面的反射。
c) 经过当前的service类的字节码来获取ServiceManager的字节码文件
d) 下一步则是将iBinder转成接口类型,须要两个aidl文件,其中一个是依赖另一个存在的,注意保证包名一致
e) 这时系统会在gen目录的com.android.internal.telephony包下自动生成一个ITelephony.java的接口文件
f) 继续代码实现反射挂断电话的操做,这时会出现不少高级的api能够供咱们使用了
// IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE) try { Class clazz = CallSmsSafeService.class.getClassLoader().loadClass("android.os.ServiceManager"); Method method = clazz.getDeclaredMethod("getService", String.class); IBinder iBinder = (IBinder) method.invoke(null, TELEPHONY_SERVICE); ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder); iTelephony.endCall(); } catch (Exception e) { e.printStackTrace(); }
g)要挂断电话还须要添加拨打电话的权限
<uses-permission android:name="android.permission.CALL_PHONE"/>
2.反射清除缓存
a)得到两个aidl文件,一个是依赖另一个存在的
b)这个时候,系统会自动生成一个接口文件,而后咱们就可使用它了
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PackageManager manager = getPackageManager(); Method[] methods = PackageManager.class.getDeclaredMethods(); for (Method method : methods) { if ("getPackageSizeInfo".equals(method.getName())) { try { method.invoke(manager, getPackageName(),new MyPackageStatsObserver()); } catch (Exception e) { e.printStackTrace(); } } } } private class MyPackageStatsObserver extends IPackageStatsObserver.Stub { @Override public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException{ long cacheSize = pStats.cacheSize; // 缓存大小 long codeSize = pStats.codeSize;// 代码大小 long dataSize = pStats.dataSize;// 数据大小 } } }
d)记得添加权限
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>