接触过Android的同学都应该知道Service,Android四大组件之一嘛,应该都很熟悉了,咋一看IntentService那又是什么鬼呢?
其实IntentService也是一个Service,是用来处异步任务的,比如说下载一个文件,处理耗时操作,当任务处理完成后这个Service会自动关闭。那么为什么需要IntentService呢?我们知道Service虽然被大家经常说是后台服务,但是Service所运行的线程其实还是主线程,不能执行耗时操作,会出现ANR导致应用卡死的假象,给用户不好的体验。所以如果我们要在Service里面处理耗时操作那就要手动去开启一个线程,google为了方便我们,就开发了IntentService给我们解决了自己手动开启线程的问题。下面我将带领大家一起来分析下IntentService
下面简单的模拟一个文件下载的操作,比如我们应用中经常使用到软件更新,当检测到软件更新的时候,自动下载apk,然后安装,这个场景最适合使用IntentService,因为下载apk的Service是一次性的,下载完成后就没必要存在可。所以我们新建一个UpdateService.java,代码如下:
package com.wms.github.intentservice;
import android.app.IntentService;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.util.Log;
/** * Created by 王梦思 on 2017/5/26. */
public class UpdateService extends IntentService {
private static final String TAG = "UpdateService";
public UpdateService(String name) {
super(name);
}
public UpdateService() {
super("");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.e("UpdateService","onHandleIntent...");
if (intent != null) {
String path = intent.getStringExtra("apkFilePath");
downloadApk(path);
}
}
private void downloadApk(String path) {
Log.e("UpdateService",path);
//模拟耗时操作,这里就不真的下载文件了
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//这里代码执行完成后,Service就停止了
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate...");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy...");
}
}
MainActivity.java代码如下:
package com.wms.github.intentservice;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
/** * Created by 王梦思 on 2017/5/26. */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.start_service).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, UpdateService.class);
intent.putExtra("apkFilePath","http://www.baidu.com/apk/demo.apk");
startService(intent);
}
});
}
}
布局文件activity_main.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.wms.github.intentservice.MainActivity">
<Button android:id="@+id/start_service" android:layout_width="match_parent" android:layout_height="50dp" android:layout_centerInParent="true" android:text="下载apk"/>
</RelativeLayout>
当我们点击下载apk按钮的时候,则会开启UpdateService,先看下UpdateService执行的时候的日志。
05-26 10:39:42.573 21936-21936/com.wms.github.intentservice E/UpdateService: onCreate...
05-26 10:39:42.574 21936-22017/com.wms.github.intentservice E/UpdateService: onHandleIntent...
05-26 10:39:42.575 21936-22017/com.wms.github.intentservice E/UpdateService: http://www.baidu.com/apk/demo.apk
05-26 10:39:42.575 21936-22017/com.wms.github.intentservice E/UpdateService: 正在下载安装包...
05-26 10:39:47.576 21936-22017/com.wms.github.intentservice E/UpdateService: 安装包下载完成...
05-26 10:39:47.581 21936-21936/com.wms.github.intentservice E/UpdateService: onDestroy...
分析下UpdateService的执行顺序,顺序依次是onCreate–>onHandleIntent–>执行任务代码–>onDestroy,所以我们一般的处理异步任务的逻辑都是在onHandleIntent里面去做的,当这里面的任务逻辑处理完成后,服务就自动销毁了,将不会占用任何的系统资源。
通过上面的简单分析,相信大家已经知道IntentService是怎么使用的,但是我们要作为一个合格的程序员,应该知其然知其所以然,下面将从源码的角度来分析下IntentService。
由于IntentService源码比较简单,我索性把他的源码贴出来,方便查看,这里我将注释都去掉了:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
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;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
可以看出IntentService的代码其实也就不到100行,还是很简单的。
当我们开启服务的时候,第一个执行的方法是onCreate方法,所以我们看下IntentService的onCreate方法里面创建了一个HandlerThread,HandlerThread其实就是一个继承Thread的类,只不过里面给我们新建了一个Looper。然后实例化了mServiceHandler,其实就是一个包含了Looper的Handler,我们一般创建一个Handler的时候都没有传递Looper,其实默认就是传递了主线程的Looper,这个主线程的Looper是在哪里创建的呢?其实是在我们应用开启的时候ActivityThread.java中的main方法里面创建的。这里扯远了,就不多说了。
当onCreate执行完成之后,就会调用onStart方法,在onStart方法里面创建了一个消息对象,通过onCreate实例化的mServiceHandler发送一个消息,这时候就会调用到IntentService 中静态内部类ServiceHandler的handleMessage方法,我们所说的onHandleIntent就是在handleMessage里面,onHandleIntent是一个抽象方法,所以这就是为什么我们继承IntentService的时候为什么需要重新onHandleIntent方法了。
当onHandleIntent执行完成之后,我们回到上面所说的handleMessage方法内部,在onHandleIntent下面还有一行代码就是stopSelf(),stopSelf就是停止当前的Service,这也就是为什么我们的异步任务处理完成后Service会自动停止了。
当Service停止时,就会调用onDestroy方法咯,整个流程到这里就讲解清楚了。总结一下,其实ItentService没什么神奇的地方,就是结合了Handler + Looper + Messeage来完成的,这个其实我们早就滚瓜烂熟了。
代码传送门:http://github.com/wms1993/blog_intentservice_demo