一 IntentService介绍
IntentService定义的三个基本点:是什么?怎么用?如何work?
官方解释如下:
//IntentService定义的三个基本点:是什么?怎么用?如何work?*/
1、IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand.
2、Clients send requests through startService(Intent) calls;
3、the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
//解释了IntentService的好处,以及How to use IntentService*/
This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
All requests are handled on a single worker thread — they may take as long as necessary (and will not block the application’s main loop), but only one request will be processed at a time.
总结IntentService的特点如下:
1、IntentService是Service类的子类,用来处理异步请求。
2、客户端可以通过startService(Intent)方法传递请求给IntentService
3、IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任务,这样以免事务处理阻塞主线程。
4、执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。
5、IntentService在处理事务时,还是采用的Handler方式,创建一个名叫ServiceHandler的内部Handler,并把它直接绑定到HandlerThread所对应的子线程。 ServiceHandler把处理一个intent所对应的事务都封装到叫做onHandleIntent的虚函数;因此我们直接实现虚函数onHandleIntent,再在里面根据Intent的不同进行不同的事务处理就可以了。
IntentService最重要的一个方法onHandleIntent:
This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().
1、该函数用于针对Intent的不同进行不同的事务处理.执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,
则自动停止Service;否则ServiceHandler会取得下一个Intent请求传人该函数来处理其所对应的任务。
2、所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),但是同一时间只处理一个请求。
IntentService的特点、优点、缺点?
IntentService的特点:
- IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue的形式;
- 由于是单线程(一个工作线程),所以所有的任务需要排队执行;/
- 避免了我们再去创建线程和管理service的结束工作;
基于以上,IntentService与Service比较的好处有:
- 第一,使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
- 第二,当操作完成时,我们不用手动停止Service。
当然,IntentService的缺点也是显而易见:
由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况;
二 DEMO实践
DEMO场景描述:
主要由MainActivity和MyIntentService构成,在MainActivity中启动服务,并传递两个参数a和b,在MyIntentService中获取参数,求和,并通过发送广播的形式向UI返回结果,然后MainActivity在接收到广播之后更新UI。
MainActivity.java主要做了三件事:
- 注册/注销广播接收器;
- 创建UI和更新UI;
- 传递参数,启动MyIntentService;
代码如下:
public class MainActivity extends AppCompatActivity { private LinearLayout ll_container; private BroadcastReceiver forSumReceiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i("TAG","onReceive ()"); if(intent.getAction()==Constans.ACTION_RESULT){ int a=intent.getIntExtra(Constans.A,0); int result=intent.getIntExtra(Constans.RESULT,0); Log.i("TAG","onReceive --result:"+result); handleResult(a,result); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ll_container= (LinearLayout)findViewById(R.id.ll_container); Log.i("TEST","MainActivity:"+android.os.Process.myTid()); registerBroadcast(); } private void handleResult(int a,int result){ TextView textView=(TextView)ll_container.findViewWithTag(a); String old=textView.getText().toString(); String newText=old.replaceAll(" 正在计算中...",String.valueOf(result)+" 计算Success"); textView.setText(newText); } private void registerBroadcast(){ IntentFilter intentFilter=new IntentFilter(); intentFilter.addAction(Constans.ACTION_RESULT); registerReceiver(forSumReceiver,intentFilter); } private int a=1; public void addTask(View view){ int b=new Random().nextInt(101)+1; MyIntentService.startMyIntentService(this,a,b); TextView textView=new TextView(this); textView.setText(a+"+"+b+"= "+ " 正在计算中..."); textView.setTag(a); ll_container.addView(textView); a++; } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(forSumReceiver); } }
MyIntentService用于接收参数,并返回计算的结果:
public class MyIntentService extends IntentService { public MyIntentService() { //必须实现父类的构造方法 super("MyIntentService"); } @Override public void onCreate() { Log.i("TEST","onCreate()"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { Log.i("TEST","onStart()"); super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("TEST","onStartCommand()"); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { Log.i("TEST", "onBind()"); return super.onBind(intent); } @Override public void onDestroy() { Log.i("TEST","onDestroy()"); super.onDestroy(); } @Override protected void onHandleIntent(Intent intent) { Log.i("TEST","onHandleIntent():"+android.os.Process.myTid()); if (intent!=null){ String action=intent.getAction(); if(Constans.ACTION_FOR_SUM.equals(action)){ int a=intent.getIntExtra(Constans.A,0); int b=intent.getIntExtra(Constans.B,0); int result=a+b; Log.i("TEST","result: "+result); handleResult(a,result); } } } private void handleResult(int a,int result){ try{ //模拟计算耗时 Thread.sleep(3000); Intent intent=new Intent(Constans.ACTION_RESULT); intent.putExtra(Constans.RESULT,result); intent.putExtra(Constans.A,a); sendBroadcast(intent); }catch (InterruptedException e){ e.printStackTrace();; } } public static void startMyIntentService(Context context,int a,int b){ Intent intent=new Intent(context,MyIntentService.class); intent.setAction(Constans.ACTION_FOR_SUM); intent.putExtra(Constans.A,a); intent.putExtra(Constans.B,b); context.startService(intent); } }
IntentService生命周期方法执行顺序如下:
07-08 10:18:51.579 com.troy.intentservicedemo I/TEST: MainActivity:30060 07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onCreate() 07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onStartCommand() 07-08 10:19:26.009 com.troy.intentservicedemo I/TEST: onStart() 07-08 10:19:26.039 com.troy.intentservicedemo I/TEST: onHandleIntent():30223 07-08 10:19:26.039 com.troy.intentservicedemo I/TEST: result: 23 07-08 10:19:29.100 com.troy.intentservicedemo I/TEST: onDestroy() 07-08 10:19:31.839 com.troy.intentservicedemo I/TEST: onCreate() 07-08 10:19:31.849 com.troy.intentservicedemo I/TEST: onStartCommand() 07-08 10:19:31.849 com.troy.intentservicedemo I/TEST: onStart() 07-08 10:19:31.869 com.troy.intentservicedemo I/TEST: onHandleIntent():30305 07-08 10:19:31.869 com.troy.intentservicedemo I/TEST: result: 52 07-08 10:19:34.899 com.troy.intentservicedemo I/TEST: onDestroy()
从上面Log中可以看出:
- UI线程的线程ID=30060,而onHandleIntent()的线程ID分别是30223,30305;由此知道onHandleIntent()方法是执行在工作线程中的;
- 并且IntentService的所有请求如果是在一个生命周期中完成的话,则所有请求是在一个工作线程中顺序执行的。否则,是在不同的工作线程中完成。
- 同时验证了:执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;
运行效果如图:
三 IntentService源码简单解析
IntentService是Service的子类,拥有Service的所有生命周期方法;同时还有自己的ServiceHandler;
ServiceHandler相关源码如下:
public abstract class IntentService extends Service { private volatile Looper mServiceLooper;//volatile关键字保证同步,保证可见性 private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); } } public IntentService(String name) {//构造方法 super(); mName = name; }
IntentService 实际上是Looper,Handler,Service 的集合体,他不仅有服务的功能,还有处理和循环消息的功能。
onCreate()的源码:创建了一个HandlerThread
@Override public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }
IntentService创建时就会创建Handler线程(HandlerThread)并且启动,然后再得到当前线程的Looper对象来初始化IntentService的mServiceLooper,接着创建mServicehandler对象。
下面是onStart()的源码: 调用mServiceHandler
@Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
当你启动IntentService的时候,就会产生一条附带startId和Intent的 Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会停止Handler 处理消息。
handleMessage处理的代码如下:
@Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); }
接着调用 onHandleIntent((Intent)msg.obj),这是一个抽象的方法,其实就是我们要重写实现的方法,我们可以在这个方法里面处理我们的工作.当任务完成时就会调用stopSelf(msg.arg1)这个方法来结束指定的工作。
stopSelf(msg.arg1):
注意下:回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.如果传入的是-1则直接销毁。
当所有的工作执行完后:就会执行onDestroy方法。
onDestroy源码如下:
@Override public void onDestroy() { mServiceLooper.quit(); }
服务结束后调用这个方法 mServiceLooper.quit()使looper停下来。
最后总结一下上述的分析:
1、 IntentService是一个基于消息的服务,每次启动该服务并不是马上处理你的工作,而是首先会创建对应的Looper,Handler并且在MessageQueue中添 加的附带客户Intent的Message对象, 当Looper发现有Message的时候接着得到Intent对象通过在 onHandleIntent((Intent)msg.obj)中调用你的处理程序. 处理完后即会停止自己的服务. 意思是Intent的生命周期跟你的 处理的任务是一致的. 所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。
2、IntentService是不适合用于bindService()这样的启动方式的。其次我们通过startService多次启动Service时,相当于在MessageQueue中添加了多个任务,就可以实现多任务按照顺序执行。
3、只有在onHandleIntent()方法中执行的代码才是在工作线程中运行的。IntentService的停止不是因为在handleMessage() 中执行了stopSelf(msg.arg1);而是系统自己停止的。