无论学什么知识点最好从其基本用法开始,而后在深刻到源码层学习会比较容易理解源码带给咱们的思想。因此我们先来看看IntentService的基本用法。java
其实很简单,遵照必定的套路就能够设计模式
好比:安全
public class MyIntentService extends IntentService { private static final String ACTION_BAZ = "com.example.comp.action.BAZ"; private static final String EXTRA_PARAM1 = "com.example.comp.extra.PARAM1"; private static final String EXTRA_PARAM2 = "com.example.comp.extra.PARAM2"; public MyIntentService() { super("MyIntentService"); setIntentRedelivery(false); } //用于启动此服务的辅助方法 public static void startActionBaz(Context context, String param1, String param2) { Intent intent = new Intent(context, MyIntentService.class); intent.setAction(ACTION_BAZ); intent.putExtra(EXTRA_PARAM1, param1); intent.putExtra(EXTRA_PARAM2, param2); context.startService(intent); Log.d("MyIntentService","startActionBaz"); Log.d("MyIntentService","threadID:" + Thread.currentThread().getId()); } @Override protected void onHandleIntent(Intent intent) { Log.d("MyIntentService","onHandleIntent:" + Thread.currentThread().getId()); if (intent != null) { final String action = intent.getAction(); if (ACTION_BAZ.equals(action)) { final String param1 = intent.getStringExtra(EXTRA_PARAM1); final String param2 = intent.getStringExtra(EXTRA_PARAM2); handleActionBaz(param1, param2); } } } private void handleActionBaz(String param1, String param2) { Log.d("MyIntentService","handleActionBaz:" + Thread.currentThread().getId()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void onDestroy() { super.onDestroy(); Log.d("MyIntentService","onDestroy:" + Thread.currentThread().getId()); } }
在前台activity中经过 MyIntentService.startActionBaz
来启动服务,你们能够注意log日志的输出查看对应的方法是在哪一个线程中执行的(一般主[ui]线程id为1,若是在对应的方法中输出的线程id为1代表是在ui线程中执行的,那么千万就不要在这样的方法中执行费时操做了,以免ANR[程序未响应]的异常)。
辅助方法中是经过startService来启动服务的,想必你们都知道在启动成功后将调用Service的onCreate和onStartCommand方法,那 咱们就能够从这两个方法开始着手进入源码分析。并发
public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } public void onDestroy() { mServiceLooper.quit();//退出Looper消息循环 }
大概能够得出结论:异步
public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
很明显就是经过ServiceHandler来发送消息(发送到了HandlerThread的Looper消息队列中),消息携带了intent对象(start Service启动Service时的intent),那么有发送消息就必定有处理消息的代码。继续查看ServiceHandler的代码发现其是IntentService的内部类,定义以下:ide
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); } }
能够看出在handleMessage中调用了onHandleIntent方法并在方法结束后stopSelf中止了Service。继续查看onHandleIntent方法的定义
IntentService.java
protected abstract void onHandleIntent(Intent intent);
OK,这个抽象方法必须在IntentService的子类中重写,那么在ServiceHandler的handleMessage中调用的将是子类中重写的onHandleIntent方法,因此在咱们的MyIntentService类中的onHandleIntent方法被调用(经过Java的多态机制实现了一个“模版方法”的设计模式)oop
到此源码基本分析结束,能够得出结论以下:源码分析
但愿按顺序执行(串行)而非并发(并行)执行的费时操做,其中每一个任务执行完毕的时间是未知的
的应用场景。若是但愿在任务结束后通知前台能够经过sendBroadCast的方式发送广播。HandlerThread类的关键代码(Service的onCreate方法中建立并start启动了线程):学习
/** 典型的建立Looper步骤: //生成Looper实例 Looper.prepare(); Looper.myLooper(); //启动Looper循环 Looper.loop(); */ public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } public Looper getLooper() { if (!isAlive()) { return null; } synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; }
这里比较难理解的是线程的安全同步代码,在onCreate方法中调用顺序以下:ui
HandlerThread thread = new HandlerThread(); thread.start(); thread.getLooper();
想必你们都知道线程的基本知识,这里就很少介绍了。在线程调用start后并不必定run方法马上获得执行(异步调用的),因此在执行thread.getLooper()时这个时候run尚未执行。so,getLooper方法内部经过加锁并有条件的wait()来一直等待mLooper不为空。在run方法中能够看到若是mLooper被初始化后会调用notifyAll()来通知全部正处于wait的线程继续执行,这时getLooper方法中的return mLooper;将获得执行。