Android 四大组件 之 Service
子曰:温故而知新,可以为师矣。 《论语》-- 孔子
一、 简介
Android
四大组件之一,特点是无需界面,用于在后台处理耗时的操作或长期任务。甚至在程序退出的情况下,我们也可以让 Service
在后台继续保持运行状态。
二、 生命周期
先来一张经典的图:
从图上分析:
Service
的生命周期会根据启动方式的不同
有不同的生命周期回调。startService
和bindService
的区别就是该service
是否可以和启动它的组件(比如Activity
)通信。
2.1 startService
方式开启服务
1)新键一个 MyService
类继承 Service
,并重写父类的 onCreate()
、onStartCommand()
、onDestroy()方法
。
public class MyService extends Service {public static final String TAG = "TAG";@Overridepublic void onCreate() {super.onCreate();Log.d(TAG,"=======onCreate=======");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG,"=======onStartCommand=======");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG,"=======onDestroy=======");}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}
2)项目中的每一个 Service
都必须在 AndroidMainfest.xml
中注册才行。
<application// .....// 在 application 节点下注册<service android:name=".MyService"/>// .....</application>
3)在 MainActivity
的布局文件添加一个启动服务按钮和一个停止服务按钮,同时在 MainActivity
中添加点击事件,分别做启动和停止服务操作。
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnStartService = findViewById(R.id.btn_start);Button btnStopService = findViewById(R.id.btn_stop);//开启服务btnStartService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startService(new Intent(MainActivity.this, MyService.class));}});//停止服务btnStopService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {stopService(new Intent(MainActivity.this,MyService.class));}});}
}
4)运行程序,点击开启服务按钮,查看 log
日志。
com.example.servicedemo D/TAG: =======onCreate=======
com.example.servicedemo D/TAG: =======onStartCommand=======
从日志中可以分析出: 当启动一个服务时,会回调 onCreate()
--> onStartCommand()
。如果此时再次点击一下开启服务按钮,那么生命周期如何?操作后查看日志。
com.example.servicedemo D/TAG: =======onCreate=======
com.example.servicedemo D/TAG: =======onStartCommand=======
com.example.servicedemo D/TAG: =======onStartCommand=======
可以看到:此时并没有走 onCreate()
方法,为什么 ???
说明 onCreate()
方法只会在 Service
第一次创建的时候调用,如果 Service
已经被创建了,那么 startService
方法不管被调用多少次,onCreate()
方法都不会被调用。
对比 Activity
,Activity
可以根据启动模式的不同可以有一个或者多个实例,虽然 Service
有两种启动方式,但是在整个系统中只会有一个 Service
实例。好比 PC 端的 C/S 模式,使用一个服务端去处理多个客户端的请求,这里就对应一个 Service
去处理来自多个 Activity
的请求。
对于 onStartCommand()
方法的返回值,再次有必要说明一下: onStartCommand()
方法必须返回一个整数,用于告知系统在服务被杀死后应该如何运行。有以下几个值:
START_NOT_STICKY
: 不会重建服务,除非还存在未发送的intent
。当服务不再是必须的,并且应用程序能够简单地重启那些还未完成的工作时,这是避免服务运行的最安全的选项。START_TICKY
:重建服务并且调用onStartCommand()
,但是不会再次送入上一个intent
,而是用空的intent
来调用onStartCommand()
。除非还有启动服务的intent
未发送完,那么这些剩下的intent
会继续发送 (适用于媒体播放器的类似服务,它们不执行命令,但需要一直运行并随时待命)。START_REDELIVER_INTENT
:重建服务且用上一个已发送过的intent
调用onStartCommand()
,任何未发送完成的intent
也会依次进入。(使用与那些需要立即恢复工作的活跃服务,比如下载文件)
5.点击停止服务按钮,查看 log
日志。
com.example.servicedemo D/TAG: =======onCreate=======
com.example.servicedemo D/TAG: =======onStartCommand=======
com.example.servicedemo D/TAG: =======onStartCommand=======
com.example.servicedemo D/TAG: =======onDestroy=======
此时服务停止,回调 onDestroy()
方法。
特别说明一下: 一旦服务开启,就和调用者 (开启者) 没有任何关系了,开启者退出,销毁(例如
Activity
的销毁),服务都在后台长期运行,开启者不能调用服务里面的方法。
好了,关于 startService
方式开启的 service
的生命周期的讲解结束啦,下面总结一下:
- 第一次启动服务,手动调用
startService()
方法,生命周期回调:onCreate()
-->onStartCommand()
,之后无论多少次启动服务,只会走onStartCommand()
方法。 - 停止服务,手动调用
unbindService()
方法,生命周期回调:onDestory()
。 - 此启动模式下的生命周期,只有
onStartCommand()
方法会多次调用,其余方法只会调用一次。
2.2 bind
方式开启服务
1)在 MyService
中 创建 MyBinder
实例,继承 Binder
,同时 onBind()
方法返回 MyBinder
实例。
public class MyService extends Service {public static final String TAG = "TAG";private MyBinder mMyBinder = new MyBinder();@Overridepublic void onCreate() {super.onCreate();Log.d(TAG,"=======onCreate=======");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG,"=======onStartCommand=======");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG,"=======onDestroy=======");}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG,"=======onBind=======");return mMyBinder;}@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG,"=======onUnbind=======");return super.onUnbind(intent);}class MyBinder extends Binder {public void startDownload(){Log.d(TAG,"=======startDownload=======");// 假设执行具体的下载任务}}
}
2. MainActivity
中 创建 MyServiceConnection
的实例,实现 ServiceConnection
接口,重写 onServiceConnected()
和 onServiceDisconnected()
方法,在 onServiceConnected()
方法中,可以拿到 MyService
中的 MyBinder
实例,可以调用 MyBinder
实例中的任何 public
方法。同时添加绑定服务操作和解绑服务操作,分别调用 bindService()
和 unbindService()
方法。
public class MainActivity extends AppCompatActivity {private MyService.MyBinder mMyBinder;private ServiceConnection mServiceConnection;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btnStartService = findViewById(R.id.btn_start);Button btnStopService = findViewById(R.id.btn_stop);Button btnBindService = findViewById(R.id.btn_bind);Button btnUnBindService = findViewById(R.id.btn_unbind);mServiceConnection = new MyServiceConnection();//开启服务btnStartService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startService(new Intent(MainActivity.this, MyService.class));}});//停止服务btnStopService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {stopService(new Intent(MainActivity.this,MyService.class));}});//绑定服务btnBindService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent bindIntent = new Intent(MainActivity.this,MyService.class);//Context.BIND_AUTO_CREATE : Activity和Service建立关联后自动创建ServicebindService(bindIntent,mServiceConnection, Context.BIND_AUTO_CREATE);}});//解绑服务btnUnBindService.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {unbindService(mServiceConnection);}});}class MyServiceConnection implements ServiceConnection{/**** @param name* @param service Service中的onBind方法返回的*/@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d("TAG", "onServiceConnected");mMyBinder = (MyService.MyBinder) service;mMyBinder.startDownload();}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.i("TAG", "onServiceDisconnected");}}
}
3.点击绑定服务,查看日志
com.example.servicedemo D/TAG: =======onCreate=======
com.example.servicedemo I/TAG: =======onBind=======
注意:
- 绑定服务不会调用
onStartCommand()
方法。 bind
方式开启的服务,绑定服务后,调用者挂了,服务也会挂了,调用者可以使用服务里面的方法。- 任何一个
Service
在整个应用程序范围内都是通用的,即MyService
不仅可以和MainActivity
建立关联,还可以和任何一个Activity
建立关联,而且建立关联时,都可以获得相同的MyBinder
实例。
4.点击解绑服务,查看日志。
com.example.servicedemo I/TAG: =======onUnbind=======
com.example.servicedemo D/TAG: =======onDestroy=======
思考: 如果点击了开启服务,同时又点击了绑定服务,那么如何销毁服务呢???
5. 点击开启服务按钮,接着点击绑定服务按钮,然后点击停止服务按钮,最后点击解绑服务按钮,查看日志。
com.example.servicedemo D/TAG: =======onCreate=======
com.example.servicedemo D/TAG: =======onStartCommand=======com.example.servicedemo I/TAG: =======onBind=======
com.example.servicedemo D/TAG: onServiceConnected
com.example.servicedemo D/TAG: =======startDownload=======com.example.servicedemo D/TAG: click Stop Service buttoncom.example.servicedemo D/TAG: click Unbind Service button
com.example.servicedemo I/TAG: =======onUnbind=======
com.example.servicedemo D/TAG: =======onDestroy=======
从日志中可以得出结论:一个 Service 必须要在既没有和任何 Activity 关联又处理停止状态的时候才会被销毁。
好了,关于 bindService
的讲解就结束啦,下面总结一下:
- 绑定服务:手动调用
bindService()
方法,生命周期回调onCreate()
-->onBind()
。 - 解绑服务:手动调用
unbindServide
方法,生命周期回调onUnbind()
-->onDestroy()
。 - 先启动服务,在绑定服务,然后解绑服务,最后停止服务,生命周期回调
onCreate()
-->onStartCommand()
-->onBind()
-->onUnBind()
-->onDestroy()
。
再强调几点说明:
startService
方式启动的service
是无法与Activity
通信的,而bindService
方式启动的servcice
是可以与Activity
通信的。startService
方式启动的service
,Activity
销毁了,此service
依然可以在后台运行,除非调用stopService()
方法停止服务;而bindService
方式启动的servcice
,一旦与之关联的所有Activity
都销毁了,service
自动销毁。
2.3 前台服务
- 前台
Service
优先级较高,不会由于系统内存不足而被回收;后台Service
优先级较低,当系统出现内存不足情况时,很有可能会被回收。
前台服务与后台服务最大的区别在于,前台服务在下拉通知栏有显示通知,但后台服务没有,只需要在原有的 Service
类对 onCreate()
方法进行稍微修改即可,代码如下:
@Overridepublic void onCreate() {super.onCreate();System.out.println("执行了onCreat()");//添加下列代码将后台Service变成前台Service//构建"点击通知后打开MainActivity"的Intent对象Intent notificationIntent = new Intent(this,MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);//新建Builer对象Notification.Builder builer = new Notification.Builder(this);builer.setContentTitle("前台服务通知的标题");//设置通知的标题builer.setContentText("前台服务通知的内容");//设置通知的内容builer.setSmallIcon(R.mipmap.ic_launcher);//设置通知的图标builer.setContentIntent(pendingIntent);//设置点击通知后的操作Notification notification = builer.getNotification();//将Builder对象转变成普通的notificationstartForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来}
三、Service 和 Thread 之间的关系
Service
和Thread
之间没有任何关系。- 调用者和
service
在同一个进程里,所以运行在主进程的main
线程中,所以不能在Service
里编写耗时代码。
其实就是要搞清楚 后台
与 子线程
是两个完全不同的概念。
Android
的后台就是指,它的运行是完全不依赖 UI 的。即使 Activity
被销毁,或者程序被关闭,只要进程还在,Service
就可以继续运行。
正确的做法是在 Service
中再创建子线程,然后在这里去处理耗时逻辑就不会阻塞主线程的运行。
start
启动服务的 Service
可以这样写:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {new Thread(new Runnable() {@Overridepublic void run() {// 开始执行后台任务}}).start();return super.onStartCommand(intent, flags, startId);
}
bind
启动服务的 Service
可以这样写:
// 参考 MyService
class MyBinder extends Binder {public void startDownload() {new Thread(new Runnable() {@Overridepublic void run() {// 执行具体的下载任务}}).start();}
}
四、远程 Service(AIDL
)
先来做一个小改动,在 MyService
的 onCreate()
方法中让线程睡眠 60 秒。
public class MyService extends Service {......@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "onCreate() executed");try {Thread.sleep(60000);} catch (InterruptedException e) {e.printStackTrace();}}......
}
重新运行后,点击一下 Start Service
按钮或 Bind Service
按钮,程序就会阻塞住并无法进行任何其它操作,过一段时间后就会弹出 ANR
的提示框。
原因想必你已经知道原因了,Service
是运行在主线程中的,不能执行耗时操作,那么如何避免这 ANR
呢???
这时候可以使用远程 Service
。将一个普通的 Service
变成远程 Service
其实很简单,只需要在注册 Service
时,将它的 process
属性变成 remote
就行。
<service android:name=".MyService"android:process=":remote"/>
现在重新运行,并没有 ANR
,原因是 MyService
已经在另外一个进程当中了,所以只会阻塞该进程中的主线程,并不会影响到当前应用程序。
为了验证说法,在 MyService
和 MainActivity
的 onCreate
方法中加入一行日志,打印出各自所在的进程 id
。
com.example.servicedemo D/TAG: process id is 8928
com.example.servicedemo:remote D/TAG: =======onCreate=======
com.example.servicedemo:remote D/TAG: process id is 8958
可以明显的看到,不仅仅是进程id不同了,就连应用程序包名也不一样了,MyService
中打印的那条日志,包名后面还跟上了:remote
标识。
这种方式有一个弊端,就是不能使用 bindService
方式了,点击 start Service
程序不会崩溃,但是点击 bind Service
会崩溃,为什么 ???
原因是 bindService
方式启动的 Service
服务,会把 MainActivity
和 MyService
建立关联,但是它们运行在两个不同的进程中,不能再用传统的方式了,此时就需要 AIDL
了。
那么什么是 AIDL
呢?
AIDL 是 Android 接口定义语言的意思,它可以用于让某个 Service 与多个应用程序组件之间进行跨进程通信(IPC),从而实现多个应用程序共享一个 Service 的功能。
下面就来说一说它的具体用法。
1) 新建 AIDL
文件
interface MyAIDLService {int plus(int a,int b);String toUpperCase(String str);
}
2)在 Service
子类中实现定义的接口方法。
public class MyServiceByAIDL extends Service {public static final String TAG = "TAG";@Overridepublic void onCreate() {super.onCreate();Log.d(TAG,"=======onCreate=======");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG,"=======onStartCommand=======");return super.onStartCommand(intent, flags, startId);}@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG,"=======onBind=======");return super.onUnbind(intent);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG,"=======onDestroy=======");}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}MyAIDLService.Stub mBinder = new MyAIDLService.Stub() {@Overridepublic void invokeMethodInMyService() {Log.d(TAG,"客户端通过AIDL与远程后台成功通信");}};
}
3) 在 AndroidMainfest.xml
中 注册服务 和 声明为远程服务。
// process=":remote" : 将本地服务设置成远程服务// exported="true" : 设置可被其他进程调用<service android:name=".MyServiceByAIDL"android:process=":remote"android:exported="true" >// 此处Intent的action必须写成“服务器端包名.aidl文件名”<intent-filter><action android:name="com.example.servicedemo.MyAIDLService"/></intent-filter></service>
4)新建一个工程,同时把之前写好的 AIDL
文件所在的包(也就是 aidl
的文件夹)一起复制到新建工程的 main
包下。
5) 在 MainActivity
里,作如下代码修改,相关注释都写在代码里了:
public class MainActivity extends AppCompatActivity {//定义aidl接口变量private MyAIDLService mMyAIDLService;//创建ServiceConnection的匿名类private ServiceConnection mServiceConnection = new ServiceConnection() {//在Activity与Service建立关联时调用@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//使用AIDLService1.Stub.asInterface()方法获取服务器端返回的IBinder对象//将IBinder对象传换成了mAIDL_Service接口对象mMyAIDLService = MyAIDLService.Stub.asInterface(service);try {//通过该对象调用在MyAIDLService.aidl文件中定义的接口方法,从而实现跨进程通信mMyAIDLService.invokeMethodInMyService();} catch (RemoteException e) {e.printStackTrace();}}//重写onServiceConnected()方法和onServiceDisconnected()方法//在Activity与Service建立关联和解除关联的时候调用@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button = findViewById(R.id.btn_bind);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定//参数与服务器端的action要一致,即"服务器包名.aidl接口文件名"Intent intent = new Intent("com.example.servicedemo.MyAIDLService");//Android5.0后无法只通过隐式Intent绑定远程Service//需要通过setPackage()方法指定包名intent.setPackage("com.example.servicedemo");//绑定服务,传入intent和ServiceConnection对象bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);}});}
}
6)点击绑定服务按钮,查看日志:
D/TAG: =======onCreate=======
D/TAG: =======onBind=========
D/TAG: 客户端通过AIDL与远程后台成功通信
从 Log
日志中,可以看到我们实现了远程通信,这就是一个最简单,最基本的 AIDL
的使用。
五、IntentService
- 作为任何一个
Android
开发,不能不知道InterService
,下面那就具体讲解一下关于IntentService
的方方面面。
5.1 什么是 IntentService
?
IntentService
是继承自 Service
, 所以本质还是一个 Service
。在 IntentService
内部维护了一个 WorkerThread
来专门处理耗时的操作,实际上他会将所有 IntentService
的业务操作都放在 WorkThread
中执行。
如果 start
了多次使用的 IntentService
,那么每一次 start
任务,都会在 WorkThread
中依次执行。IntentService
在执行完这些任务之后,会调用 stopSelf()
结束自己。
5.2 IntentService
的特点
- 创建独立的
WorkThread
来处理所有的Intent
请求。 - 创建独立的
WorkThread
来处理onHandleIntent()
的实现代码,无需担心多线程问题。 - 所有请求完成后,
IntentService
会自动停止。 onBind()
默认返回null
,不要去实现它,不要用bindService()
绑定一个IntentService
。onStartCommand
提供了默认的实现,会将请求的Intent
添加到队列中。
5.3 IntentService
的代码实现
1)创建 MyIntentService
继承 IntentService
。提供一个空参的构造方法,同时在 onHandleIntent
中执行耗时操作,也能在此方法中接收 intent
传来的参数。
public class MyIntentService extends IntentService {private static final String TAG = "TAG";/*** // 这里必须有一个空参数的构造实现父类的构造,否则会报异常* // java.lang.InstantiationException: java.lang.Class<com.example.intentservicedemo.MyIntentService> has no zero argument constructor*/public MyIntentService() {super("");}@Overridepublic void onCreate() {super.onCreate();Log.d(TAG,"=====onCreate======");}@Overrideprotected void onHandleIntent(@Nullable Intent intent) {Log.d(TAG,"工作线程是:"+ Thread.currentThread().getName());String task = intent.getStringExtra("task");Log.d(TAG,"任务是:"+task);for (int i =0;i<3;i++){try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) {Log.d(TAG,"onStartCommand,startId: "+startId);return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG,"onDestroy");}
}
2)在 MainActivity
中点击开启服务。同时不要忘记,在 AndroidMinfest.xml
文件中给 MyIntentService
注册。
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,MyIntentService.class);intent.putExtra("task","播放音乐");startService(intent);intent.putExtra("task","播放视频");startService(intent);intent.putExtra("task","播放图片");startService(intent);}});
3)运行程序,查看日志:
com.example.intentservicedemo D/TAG: =====onCreate======
com.example.intentservicedemo D/TAG: onStartCommand,startId: 1
com.example.intentservicedemo D/TAG: 工作线程是:IntentService[]
com.example.intentservicedemo D/TAG: 任务是:播放音乐
com.example.intentservicedemo D/TAG: onStartCommand,startId: 2
com.example.intentservicedemo D/TAG: onStartCommand,startId: 3
com.example.intentservicedemo D/TAG: 工作线程是:IntentService[]
com.example.intentservicedemo D/TAG: 任务是:播放视频
com.example.intentservicedemo D/TAG: 工作线程是:IntentService[]
com.example.intentservicedemo D/TAG: 任务是:播放图片
com.example.intentservicedemo D/TAG: onDestroy
从上面的日志分析:
onCreate
只执行了一次,onStartCommand
执行了三次,说明只有1
个实例。- 播放音乐,播放视频,播放图片是顺次执行的,最后一个任务执行完,回调了
onDestroy()
方法。符合所有请求完成后,IntentService
会自动停止的特点。
通过上面的简单示例,是不是发现 IntentService
蛮简单地嘛,下面我们从源码来分析一波,一探究竟。
问题一:IntentService 如何单独开启一个新的工作线程?
IntentService
源码中的 onCreate()
方法:
@Overridepublic void onCreate() {// TODO: It would be nice to have an option to hold a partial wakelock// during processing, and to have a static startService(Context, Intent)// method that would launch the service & hand off a wakelock.super.onCreate();/*** 1. 通过实例化 HandlerThread 新建线程。* 2. HandlerThread 就是一个带有 handler 的 Thread。* 3. 在自定义的MyService里面,构造方法写的是super(""),如果写的不是空串,日志打印就应该是"工作线程是: IntentService[我们定义的名称]"。**/HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");thread.start();// 获取这个线程的looper,赋给内部维护的 LoopermServiceLooper = thread.getLooper();// 新建 mServiceHandler ,绑定上述获得 LoopermServiceHandler = new ServiceHandler(mServiceLooper);}
ServiceHandler
源码分析:
private final class ServiceHandler extends Handler {// 构造函数public ServiceHandler(Looper looper) {super(looper);}// IntentService的handleMessage()把接收的消息交给onHandleIntent()处理@Overridepublic void handleMessage(Message msg) {// onHandleIntent 方法在工作线程中执行// onHandleIntent() = 抽象方法,使用时需重写 onHandleIntent((Intent)msg.obj);// 执行完调用 stopSelf() 结束服务stopSelf(msg.arg1);}
}/** * onHandleIntent()源码分析* onHandleIntent() = 抽象方法,使用时需重写**/ @WorkerThreadprotected abstract void onHandleIntent(Intent intent);
问题二:IntentService
如何通过 onStartCommand()
将 Intent
传递给服务并且一次插入到工作队列中?
/** * onStartCommand()源码分析* onHandleIntent() = 抽象方法,使用时需重写**/ public int onStartCommand(Intent intent, int flags, int startId) {// 调用onStart()->>分析1onStart(intent, startId);return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}/** * 分析1:onStart(intent, startId)**/ public void onStart(Intent intent, int startId) {// 1. 获得ServiceHandler消息的引用Message msg = mServiceHandler.obtainMessage();msg.arg1 = startId;// 2. 把 Intent参数 包装到 message 的 obj 发送消息中,//这里的Intent = 启动服务时startService(Intent) 里传入的 Intentmsg.obj = intent;// 3. 发送消息,即 添加到消息队列里mServiceHandler.sendMessage(msg);
}
好了,关于 IntentService
的源码解读就差不多了,下面有两点注意事项:
- 若一个任务正在
IntentService
中执行,此时再发送一个新的任务,此任务会等到前一个任务结束后才开始执行。理由是onCreate()
方法只执行一次,即只会创建一个工作线程,多次调用只是把消息加入消息队列中等待执行而已。 - 不建议通过
bindService
启动IntentService
。理由是此模式不会调用onStartcommand
方法,消息不会发送到消息队列中,那么onHandleIntent
不会回调,无法实现多线程操作。
写在文末
纸上得来终觉浅,绝知此事要躬行。 《冬夜读书示子聿》-- 陆游
至此,Service
的基础知识点算是梳理了一遍,各位看官食用愉快。
码字不易,如果本篇文章对您哪怕有一点点帮助,请不要吝啬您的点赞,我将持续带来更多优质文章。
Android 四大组件 之 Service相关推荐
- android java service_[Java教程]Android四大组件之Service浅见
[Java教程]Android四大组件之Service浅见 0 2014-04-04 18:00:28 Service 是Android四大组件之一,可以在不显示界面的情况下在后台运行.还有一个作用是 ...
- 下面不是android四大组件之一的是,Android四大组件之一 Service
Service是长期在后台运行的没界面的Android四大组件之一,默认是运行在主线程中的,如果在service中执行耗时操作超过20秒没响应的话就会造成ANR,所以可以使用IntentService ...
- Android 四大组件之——Service(一)
一.什么是服务 服务,是Android四大组件之一, 属于 计算型组件. 长期后台运行的没有界面的组件 ,特点是无用户界面.在后台运行.生命周期长 二,什么时候使用服务? 天气预报:后台的连接服务 ...
- Android四大组件(四) Service
Service 服务 Service 服务 介绍 开启服务 停止服务 start方式开启服务的特点面试 bindService 方式开启服务的特点面试 可以使用Service开启特殊的广播接收者 bi ...
- 浅谈Android四大组件之Service
一:Service简介 Android开发中,当需要创建在后台运行的程序的时候,就要使用到Service. 1:Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件.其他应用组件 ...
- android四大组件 服务,Android四大组件之Service
Service Service(服务)是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件.服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行. 此外,组件可以绑定到 ...
- Android四大组件之Service详解
1. service是什么?及其生命周期? 在前台不可见,但是承担大部分数据处理工作(劳模),它和Activity的地位是并列的,区别在于:Activity运行与前台,Service运行于后台,没有图 ...
- android四大组件之Service 注册广播接收者
广播的注册一共有两种,一种就是用清单文件注册,还有另外一种就是用代码注册,代码注册比较灵活,可以在需要的时候注册,不需要的时候解除注册 用服务注册广播首先要开启服务, 然后在服务oncreate方法里 ...
- [Android]Android四大组件之Service总结
一.Service介绍 Service是Android中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要长期运行的task.Service的运行不需要依赖于任何用户界面,即 ...
最新文章
- python seaborn 热图 值对应颜色_Python数据分析之Seaborn(热图绘制)
- mysql 10 进制 转36_mysql 10进制与35进制之间的转换 注意Power处理bigint的问题
- 大循环在内,小循环主外为什么会效率高
- 设计模式学习笔记——目录
- 我有单片机,你有酒吗?
- 11 个重要的数据库设计规则
- Vlan和vtp重要的配置命令
- MySQL数据库select语句的使用方法
- php gmssl,golang gmssl编译不过
- 0xc0000225无法进系统_手把手研习win10系统出现0xc0000225无法进入系统的方法
- 15.元组(低调的元组,不一样的精彩)
- 线性回归中常见的一些统计学术语(RSE RSS TSS ESS MSE RMSE R2 Pearson's r)
- Samba误删除文件恢复(开启回收站)
- 人机交互设计(HCI)的七原则
- 以太猫合约之数据合约分析(二)
- Latex使用\usepackage{hyperref}报错:paragraph ended before hy@setref@link was complete
- 继承-----具体表继承-----每个子类一张表
- HYKSVCAO2V4F3电液伺服阀控制器
- 微信小程序调用阿里OCR识别
- blast中evalue和bitscore的理解
热门文章
- 人人小目标:”人寿保险为什么对女性如此重要?“
- matlab调整legend大小,[转载]【matlab】MATLAB中调整legend的大小位置
- Android---网络交互之登录嘀咕网
- 第7篇:SELECT条件查询
- 一、C语言创建桌面程序: 第一个桌面程序
- 魅蓝3 原声android,#原创新人# 一个初当煤油的体验 — MEIZU 魅蓝3 开箱测评
- Oracle查询100万到200万之间的数据
- DNF搬砖小妙招:如何搭建设备网络
- CPGAN Content-Parsing Generative Adversarial Networks for Text-to-ImageSynthesis
- java如何倒置矩阵_java – 如何创建逆变换矩阵