标签: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