标签:sys 原理 launcher 读写 pat 音乐 区别 atm pen
Android 有一段时间了,想必不少人也和我一样,平时经常东学西凑,感觉知识点有些凌乱难成体系。所以趁着这几天忙里偷闲,把学的东西归纳下,捋捋思路。这篇文章主要针对
Service相关的知识点,进行详细的梳理,祝大家食用愉快!

仓库内容与博客同步更新。由于我在 稀土掘金 简书 CSDN 博客园 等站点,都有新内容发布。所以大家可以直接关注该仓库,以免错过精彩内容!


Service (服务) 是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。Activity ),服务一旦被启动将在后台一直运行,即使启动服务的组件( Activity )已销毁也不受影响。IPC )。
UI 界面Service 的适用场景应该具备以下条件:并不依赖于用户可视的 UI 界面(当然,这一条其实也不是绝对的,如前台 Service 就是与 Notification 界面结合使用的)
具有较长时间的运行特性
注意: 是运行在主线程当中的

服务进程是通过 startService() 方法启动的进程,但不属于前台进程和可见进程。例如,在后台播放音乐或者在后台下载就是服务进程。
系统保持它们运行,除非没有足够内存来保证所有的前台进程和可视进程。

Service 的生命周期 的基本流程


定义一个类继承 Service
在 Manifest.xml 文件中配置该 Service
使用 Context 的 startService(intent) 方法开启服务。
使用 Context 的 stopService(intent) 方法关闭服务。
该启动方式,app 杀死、Activity 销毁没有任何影响,服务不会停止销毁。

创建 BindService 服务端,继承 Service 并在类中,创建一个实现 IBinder 接口的实例对象,并提供公共方法给客户端( Activity )调用。
从 onBinder() 回调方法返回该 Binder 实例。
在客户端( Activity )中, 从 onServiceConnection() 回调方法参数中接收 Binder ,通过 Binder 对象即可访问 Service 内部的数据。
在 manifests 中注册 BindService , 在客户端中调用 bindService() 方法开启绑定 Service , 调用 unbindService() 方法注销解绑 Service 。
该启动方式依赖于客户端生命周期,当客户端 Activity 销毁时, 没有调用 unbindService() 方法 , Service 也会停止销毁。

在 Service 的生命周期中,被回调的方法比 Activity 少一些,只有 onCreate , onStart , onDestroy , onBind 和 onUnbind 。
通常有两种方式启动一个 Service , 他们对 Service 生命周期的影响是不一样的。
startService
Service 会经历 onCreate 到 onStart ,然后处于运行状态,stopService 的时候调用 onDestroy如果是调用者自己直接退出而没有调用
stopService的话,Service会一直在后台运行。
bindService
Service 会运行 onCreate ,然后是调用 onBind , 这个时候调用者和 Service 绑定在一起。调用者退出了,Srevice 就会调用 onUnbind -> onDestroyed 方法。
所谓绑定在一起就共存亡了。调用者也可以通过调用
unbindService方法来停止服务,这时候Srevice就会调用onUnbind->onDestroyed方法。

一个原则是 Service 的 onCreate 的方法只会被调用一次,就是你无论多少次的 startService 又 bindService ,Service 只被创建一次。
如果先是 bind 了,那么 start 的时候就直接运行 Service 的 onStart 方法,如果先是 start ,那么 bind 的时候就直接运行 onBind 方法。
如果 service 运行期间调用了 bindService ,这时候再调用 stopService 的话,service 是不会调用 onDestroy 方法的,service 就 stop 不掉了,只能调用 UnbindService , service 就会被销毁
如果一个 service 通过 startService 被 start 之后,多次调用 startService 的话,service 会多次调
用 onStart 方法。多次调用 stopService 的话,service 只会调用一次 onDestroyed 方法。
如果一个 service 通过 bindService 被 start 之后,多次调用 bindService 的话,service 只会调用一次 onBind 方法。多次调用 unbindService 的话会抛出异常。



thread 是程序执行的最小单元,他是分配 cpu 的基本单位安卓系统中,我们常说的主线程,UI 线程,也是线程的一种。当然,线程里面还可以执行一些耗时的异步操作。service 大家记住,它是安卓中的一种特殊机制,service 是运行在主线程当中的,所以说它不能做耗时操作,它是由系统进程托管,其实 service 也是一种轻量级的 IPC 通信,因为 activity 可以和 service 绑定,可以和 service 进行数据通信。activity 和 service 是处于不同的进程当中,所以说它们之间的数据通信,要通过 IPC 进程间通信的机制来进行操作。
UI 线程的绘制,UI 线程里面绝对不能做耗时操作,这里是最基本最重要的一点。(这是 Thread 在实际开发过程当中的应用)service 是安卓当中,四大组件之一,一般情况下也是运行在主线程当中,因此 service 也是不可以做耗时操作的,否则系统会报 ANR 异常( ANR 全称:Application Not Responding ),就是程序无法做出响应。service 里面进行耗时操作,一定要记得开启单独的线程去做。
UI 线程的时候,都应该使用工作线程,也就是开启一个子线程的方式。UI 线程不被占用,而影响用户体验。service 来说,我们经常需要长时间在后台运行,而且不需要进行交互的情况下才会使用到服务,比如说,我们在后台播放音乐,开启天气预报的统计,还有一些数据的统计等等。
Thread 的运行是独立于 Activity 的,也就是当一个 Activity 被 finish 之后,如果没有主动停止 Thread 或者 Thread 中的 run 没有执行完毕时那么这个线程会一直执行下去。Activity 被 finish 之后,你不再持有该 Thread 的引用。Activity 中对同一 Thread 进行控制。
service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
Service 不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在 Service 中编写耗时的逻辑和操作(比如:网络请求,拷贝数据库,大文件),否则会引起 ANR 。
如果想在服务中执行耗时的任务。有以下解决方案:
service 中开启一个子线程new Thread(){}.start();
IntentService 异步管理服务( 有关 IntentService 的内容在后文中给出 )
service 所运行的进程, Service 和 activity 是运 行在当前 app 所在进程的 main thread ( UI 主线程)里面。Service 和 Activity 在同一个线程,对于同一 app 来说默认情况下是在同一个线程中的 main Thread ( UI Thread )service 执行所在的进程 ,让 service 在另 外的进程中执行 Service 不死之身onStartCommand 方法中将 flag 设置为 START_STICKY ;<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" >
</service>
return Service.START_STICKY;
android:priority<!--设置服务的优先级为MAX_VALUE-->
<service android:name=".MyService"
android:priority="2147483647"
>
</service>
onStartCommand 方法中设置为前台进程@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification(R.mipmap.ic_launcher, "服务正在运行",System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent,0);
RemoteViews remoteView = new RemoteViews(this.getPackageName(),R.layout.notification);
remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
remoteView.setTextViewText(R.id.text , "Hello,this message is in a custom expanded view");
notification.contentView = remoteView;
notification.contentIntent = pendingIntent;
startForeground(1, notification);
return Service.START_STICKY;
}
onDestroy 方法中重启 service@Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, MyService.class));
}
AlarmManager.setRepeating(…) 方法循环发送闹钟广播, 接收的时候调用 service 的 onstart 方法Intent intent = new Intent(MainActivity.this,MyAlarmReciver.class);
PendingIntent sender = PendingIntent.getBroadcast( MainActivity.this, 0, intent, 0);
// We want the alarm to go off 10 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
//重复闹钟
/**
* @param type
* @param triggerAtMillis t 闹钟的第一次执行时间,以毫秒为单位
* go off, using the appropriate clock (depending on the alarm type).
* @param intervalMillis 表示两次闹钟执行的间隔时间,也是以毫秒为单位
* of the alarm.
* @param operation 绑定了闹钟的执行动作,比如发送一个广播、给出提示等等
*/
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 2 * 1000, sender);
SDK 唤醒 APP , 例如 Jpush
PS: 以上这些方法并不代表着你的Service就永生不死了,只能说是提高了进程的优先级。迄今为止我没有发现能够通过常规方法达到流氓需求 (通过长按home键清除都清除不掉) 的方法,目前所有方法都是指通过Android的内存回收机制和普通的第三方内存清除等手段后仍然保持运行的方法,有些手机厂商把这些知名的app放入了自己的白名单中,保证了进程不死来提高用户体验(如微信、app一样躲避不了被杀的命运。
Interservice 都没听说过,那就有点那个啥了

IntentService 是 Service 的子类,比普通的 Service 增加了额外的功能。
我们常用的 Service 存在两个问题:
Service 不会专门启动一条单独的进程,Service 与它所在应用位于同一个进程中
Service 也不是专门一条新线程,因此不应该在 Service 中直接处理耗时的任务

会创建独立的 worker 线程来处理所有的 Intent 请求
会创建独立的 worker 线程来处理 onHandleIntent() 方法实现的代码,无需处理多线程问题
所有请求处理完成后,IntentService 会自动停止,无需调用 stopSelf() 方法停止 Service
为 Service 的 onBind() 提供默认实现,返回 null
为 Service 的 onStartCommand 提供默认实现,将请求 Intent 添加到队列中

Service 是用于后台服务的
Service 这个概念Service 不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在 Service 中编写耗时的逻辑和操作,否则会引起 ANR 。也就是,service 里面不可以进行耗时的操作。虽然在后台服务。但是也是在主线程里面。
service 来管理的时候,就需要引入 IntentService 。
IntentService 是继承 Service 的,那么它包含了 Service 的全部特性,当然也包含 service 的生命周期。service 不同的是,IntentService 在执行 onCreate 操作的时候,内部开了一个线程,去你执行你的耗时操作。
protected abstract void onHandleIntent(Intent intent)IntentService 是一个通过 Context.startService(Intent) 启动可以处理异步请求的 Service
IntentService 和重写其中的 onHandleIntent(Intent) 方法接收一个 Intent 对象 , 在适当的时候会停止自己 ( 一般在工作完成的时候 ) 。
Looper ,Handler 并且在 MessageQueue 中添加的附带客户 Intent 的 Message 对象。Looper 发现有 Message 的时候接着得到 Intent 对象通过在 onHandleIntent((Intent)msg.obj) 中调用你的处理程序,处理完后即会停止自己的服务。Intent 的生命周期跟你的处理的任务是一致的,所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。IntentService 的特征有:
会创建独立的 worker 线程来处理所有的 Intent 请求;
会创建独立的 worker 线程来处理 onHandleIntent() 方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService会自动停止,无需调用 stopSelf() 方法停止 Service ;


Activity 通过 bindService(Intent service, ServiceConnection conn, int flags) 跟 Service 进行绑定,当绑定成功的时候 Service 会将代理对象通过回调的形式传给 conn ,这样我们就拿到了 Service 提供的服务代理对象。
在 Activity 中可以通过 startService 和 bindService 方法启动 Service。一般情况下如果想获取 Service 的服务对象那么肯定需要通过 bindService() 方法,比如音乐播放器,第三方支付等。
如果仅仅只是为了开启一个后台任务那么可以使用 startService() 方法。

他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都属于 Android 的四大组件。他俩都是 Context 类的子类 ContextWrapper 的子类,因此他俩可以算是兄弟关系吧。
不过他们各有各自的本领,Activity 负责用户界面的显示和交互,Service 负责后台任务的处理。
Activity 和 Service 之间可以通过 Intent 传递数据,因此可以把 Intent 看作是通信使者。

对于同一 app 来说默认情况下是在同一个线程中的,main Thread ( UI Thread )。

Context 上下文,而 Service 本身就是 Context 的子类Service 里面弹吐司是完全可以的。比如我们在 Service 中完成下载任务后可以弹一个吐司通知给用户。

Server 端将目前的下载进度,通过广播的方式发送出来,Client 端注册此广播的监听器,当获取到该广播后,将广播中当前的下载进度解析出来并更新到界面上。Activity 、Service 以及应用程序之间,就可以通过广播来实现交互。
SharedPreferences 来实现共享,当然也可以使用其它 IO 方法实现,通过这种方式实现交互时需要注意,对于文件的读写的时候,同一时间只能一方读一方写,不能两方同时写。Server 端将当前下载进度写入共享文件中,Client 端通过读取共享文件中的下载进度,并更新到主界面上。Messenger 交互 ( 信使交互 )
Messenger 翻译过来指的是信使,它引用了一个 Handler 对象,别人能够向它发送消息 ( 使用 mMessenger.send ( Message msg ) 方法)。Message 通信,在服务端使用 Handler 创建一个 Messenger ,客户端只要获得这个服务端的 Messenger 对象就可以与服务端通信了Server 端与 Client 端之间通过一个 Messenger 对象来传递消息,该对象类似于信息中转站,所有信息通过该对象携带
Activity 与 Service 交互的目的,我们通过在 Activity 和 Service 之间架设一座桥樑,从而达到数据交互的目的,而这种实现方式和 AIDL 非常类似Server 端用一个类继承自 Binder 并实现该接口,覆写了其中获取当前下载进度的方法。Client 端通过 ServiceConnection 获取到该类的对象,从而能够使用该获取当前下载进度的方法,最终实现实时交互。AIDL 交互
AIDL 来实现,可以进行进程间通信,这种服务也就是远程服务。AIDL 属于 Android 的 IPC 机制,常用于跨进程通信,主要实现原理基于底层 Binder 机制。


Service 其实就是背地搞事情,又不想让别人知道Service 设计的初衷Service 为什么被设计出来
Service 的定义,我们可以知道需要长期在后台进行的工作我们需要将其放在 Service 中去做。Activity 中来执行的工作就必须得放到 Service 中去做。Activity 中做的话,那么 Activity 退出被销毁了的话,那这些功能也就停止了,这显然是不符合我们的设计要求的,所以要将他们放在 Service 中去执行。
START_STICKY :service 进程被 kill 掉,保留 service 的状态为开始状态,但不保留递送的 intent 对象。service, 由于服务状态为开始状态,所以创建服务后一定会调用 onStartCommand ( Intent, int, int ) 方法。service , 那么参数 Intent 将为 null 。START_NOT_STICKY :onStartCommand 后 , 服务被异常 kill 掉 ,系统不会自动重启该服务。START_REDELIVER_INTENT:Intent 。onStartCommand 后,服务被异常 kill 掉START_STICKY_COMPATIBILITY:START_STICKY 的兼容版本 , 但不保证服务被 kill 后一定能重启。
Service 中执行网络操作onStartCommand() 方法中可以执行网络操作
在 AndroidManifest.xml 文件中对于 intent-filter 可以通过 android:priority = “1000” 这个属性设置最高优先级,1000 是最高值,如果数字越小则优先级越低,同时实用于广播。
在 onStartCommand 里面调用 startForeground() 方法把 Service 提升为前台进程级别,然后再 onDestroy 里面要记得调用 stopForeground () 方法。
onStartCommand 方法,手动返回 START_STICKY 。

onDestroy 方法里发广播重启 service 。service + broadcast 方式,就是当 service 走 ondestory 的时候,发送一个自定义的广播service 。( 第三方应用或是在 setting 里-应用强制停止时,APP 进程就直接被干掉了,onDestroy 方法都进不来,所以无法保证会执行 )Service 状态。Service 是否还存活。Application 加上 Persistent 属性。
onUnbind() 方法返回 true 的情况下会执行 , 否则不执行。Android Service 相关的知识点。由于篇幅原因,诸如 InterService 具体使用方法等,没办法详细的介绍,大家很容易就能在网上找到资料进行学习。重点:关于 Android 的四大组件,到现在为止我才总结完 Activity 和 Service,我将继续针对,BroadcastRecevier ContentProvider 等,以及四大组件之外的,事件分发、滑动冲突、新能优化等重要模块,进行全面总结,欢迎大家关注_yuanhao 的 博客园 ,方便及时接收更新由于我在「稀土掘金」「简书」「CSDN」「博客园」等站点,都有新内容发布。所以大家可以直接关注我的 GitHub 仓库,以免错过精彩内容!
1W 多字长文,加上精美思维导图,记得点赞哦,欢迎关注 _yuanhao 的 博客园 ,我们下篇文章见!
相关文章均可在我的主页、GitHub 上看到,这里限于篇幅原因,也为了保持界面整洁,让大家能有跟舒心的阅读体验就不给出了,我们下篇文章不见不散!
23 个重难点突破,带你吃透 Service 知识点「长达 1W+ 字」
标签:sys 原理 launcher 读写 pat 音乐 区别 atm pen
原文地址:https://www.cnblogs.com/yuanhao-1999/p/11785430.html