IntentService的Demo程序
IntentService常被用于处理异步任务,使用的步骤是,先继承IntentService,再在handleIntent方法里写业务逻辑。handleIntent是在子线程执行的,所以不必担心ANR之类的问题,可以执行IO操作,下载等操作,且当执行完后会自动销毁,很方便。
先写一个简单的Demo。
CountService.java:
public class CountService extends IntentService { public final static String EXTRA_NUMBER = "extra_number"; public String TAG = CountService.class.getSimpleName(); public CountService() { super("CountService"); } @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { Log.e(TAG,"onStartCommand -->> startId : "+startId); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(@Nullable Intent intent) { // 通过intent来接收传递过来的数据,这里运行的线程为子线程,执行完后,这个Service就会销毁 int count = intent.getIntExtra(EXTRA_NUMBER, 1); for (int i = 0 ; i < count ; i++ ){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Log.e(TAG,"onHandleIntent --> counting "+i); } Log.e(TAG,"onHandleIntent count end"); } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG,"onDestroy"); } }
只听到从知秋君办公室传来知秋君的声音: 芳草已云暮,故人殊未来。有谁来对上联或下联?
CountActivity.java:
此代码由一叶知秋网-知秋君整理public class CountActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 这个例子中布局什么的无所谓 setContentView(R.layout.activity_test); Intent intent = new Intent(this,CountService.class); intent.putExtra(CountService.EXTRA_NUMBER,10); startService(intent); Intent intent2 = new Intent(this,CountService.class); intent2.putExtra(CountService.EXTRA_NUMBER,5); startService(intent2); } }
当我们执行完后查看log信息:
分析一下这个log信息,在发送两个任务过去后,发现onStartCommand方法先执行,之后一个任务执行完后(onHandleIntent count end),再执行下一个任务,所有任务执行完后,这个Service就被销毁了(onDestroy)。
Demo的运行情况就讲到这里,下面我们通过源码,来揭开IntentService的神秘面纱。
源码分析
IntentService继承于Service,是一个抽象类。代码量不太多,只有180行左右,所以读起来也不是特别复杂。
先看IntentService的成员变量:
- String mName ; 这是IntentService所在线程的名字,可在声明一个IntentService的时候,用IntentService的构造方法 IntentService(String name)从外部传入进来。
- boolean mRedelivery; Redelivery是重发的意思,看一看与该成员变量有关的方法 setIntentRedelivery(boolean enable):
/** * Sets intent redelivery preferences. Usually called from the constructor * with your preferred semantics. * * <p>If enabled is true, * {@link #onStartCommand(Intent, int, int)} will return * {@link Service#START_REDELIVER_INTENT}, so if this process dies before * {@link #onHandleIntent(Intent)} returns, the process will be restarted * and the intent redelivered. If multiple Intents have been sent, only * the most recent one is guaranteed to be redelivered. * * <p>If enabled is false (the default), * {@link #onStartCommand(Intent, int, int)} will return * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent * dies along with it. */ public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; }
大致意思是设置重发的偏好。
如果为true, onStartCommand()方法会返回START_REDELIVER_INTENT,所以这个进程如果在onHandleIntent()没有执行的时候死亡,这个进程会重新开启并且intent会重新传输。如果多个Intent已经被发出,只有最近的那个能保证被重新传输。
如果为false,onStartCommand()方法会返回START_NOT_STICKY,如果进程死了,那么这个Intent也随着一起死了。
- ServiceHandler mServiceHandler;
ServiceHandler 是IntentService的内部类,继承于Handler。
此代码由一叶知秋网-知秋君整理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() 这个方法,这不就是执行异步任务的那个需要重写的方法吗?执行完onHanderIntent()后,就执行stopSelf(),所以IntentService就被销毁了。
- Looper mServiceLooper; 这个Looper是实例化ServiceHandler时传递进去的Looper,这个Looper是子线程的。这个Looper在onCreate()方法里面被实例化。
接下来再来看它的方法,我们将通过方法将IntentService的工作流程和它的成员变量串连起来。
- onCreate()方法:
@Override public 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(); // HandlerThread继承于Thread,可见这是一个子线程 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); // HandlerThread里面的Looper,那就是说这个mServiceLooper是子线程的Looper mServiceLooper = thread.getLooper(); // 传入了子线程的Looper--mServiceLooper来实例化ServiceHandler,ServiceHandler的handleMessage方法是在子线程中进行的 mServiceHandler = new ServiceHandler(mServiceLooper); }
由于IntentService继承于Service,所以也同样有一样的生命周期。当实例化了一个IntentService后,后走onCreate()、onStart(),当用Intent开启一个Service时,会调用onStartCommand()。由于这里的HandlerThread是Thread的子类,它的Looper是子线程的Looper,这样ServiceHandler的构造方法传入的是子线程的Looper,所以ServerHandler的handlerMessage()方法是在子线程中进行的。
- onStart()方法:
@Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
在这里intent对象和id,被装进Message对象中,然后发送到ServiceHandler对象中。前面已经提到IntentService里面的ServiceHandler的handleMessage():
public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); // 执行完后就停止服务 }
从这里调用到了onHandleIntent()方法,从而执行到重写的onHandleIntent()的代码。
- onStartCommand()方法:
@Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; }
Service类从这里接收到Intent对象,然后调用onStart()方法,就执行到了onHandleIntent()的代码。
来回顾一下下面的代码:
Intent intent = new Intent(this,CountService.class); intent.putExtra(CountService.EXTRA_NUMBER,10); startService(intent);
当这段代码被执行,CountService会被实例化,走生命周期的 onCreate()方法,创建 HandlerThread对象,创建在子线程中执行的ServiceHandler,调用了startService(intent)则会执行到onStartCommand()方法,再调用onStart()方法,把intent对象通过Message传递到handleIntent()方法中。