Android IntentService使用全面介绍及源码解析

一 IntentService介绍

澳门新葡亰网站注册,IntentService

在实际开发过程中会有这样的一个需求,我们需要运行一个任务,并且只需要在后台默默运行即可,那么这样的需求,我们一般会在
activity 中去开启一个线程,让其去跑这个任务,但是 activity
在被切换到后台并且因为内存不足时会被回收。不过还有一种方式可以解决那就是使用
Service 的方式实现,在 Service 中开启子线程执行耗时操作,并且 service
的优先级高, 不易被回收。不过 google 为了方便开发者使用,提供了一个
IntentService 这个类。下面是 google 对这个类的描述:

/**
 * IntentService is a base class for {@link Service}s that handle asynchronous
 * requests (expressed as {@link Intent}s) on demand.  Clients send requests
 * through {@link android.content.Context#startService(Intent)} calls; the
 * service is started as needed, handles each Intent in turn using a worker
 * thread, and stops itself when it runs out of work.
 *
 * <p>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 {@link #onHandleIntent(Intent)}.  IntentService
 * will receive the Intents, launch a worker thread, and stop the service as
 * appropriate.
 *
 * <p>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是继承Service异步请求任务类,内部维护了HandlerThread和Handler,可用于执行后台耗时任务。所有的请求都只会在一个单一的线程去执行,并且一次只会去执行一个请求,队列的方式顺序执行所有的任务完成之后会自己去停止服务。正在执行的任务是无法被打断的。使用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的子类MyIntentService

    IntentService 是一个抽象类,需要子类实现,并重写 onHandleIntent
    方法,它是一个处理接收到服务的回调方法。

public class MyIntentService extends IntentService {
    public static final String TAG = MyIntentService.class.getSimpleName();

    public MyIntentService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        if (intent != null) {
            String task = intent.getStringExtra("task");
            Log.e(TAG,"onHandleIntent:"+task);

            if("open".equals(task)) {
                //表示要处理的意图
                SystemClock.sleep(3000);
                Log.e(TAG,"要特殊处理的意图:"+task);
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "MyIntentService 被销毁了");
    }
}
  • 在清单文件配置,代码不贴了。
  • 开启服务

Intent service = new Intent(this, MyIntentService.class);

service.putExtra("task", "close1");
startService(service);

service.putExtra("task", "close2");
startService(service);

service.putExtra("task", "open");
startService(service);
  • 结果

从运行结果可以看出IntentService是逐个去执行任务的,只有最后一个任务执行完毕之后才会去停止服务

onHandleIntent:close1
onHandleIntent:close2
onHandleIntent:open
要特殊处理的意图:open
MyIntentService 被销毁了

总结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#onCreate()

    服务第一次被创建就会执行 onCreate()
    方法,其主要分为两步:第一步在该方法中创建线程HandlerThread,thread.start();
    并开启线程,查阅 HandlerThread#run()
    方法源码可以知道,HandlerThread 绑定的 Looper 会调用
    Looper.loop()开启轮训了,等待消息的到来。
    第二步是创建 ServiceHandler,并将该 ServiceHandler
    绑定HandlerThread创建的Looper对象,这样通过mServiceHandler发送的消息会被发送到HandlerThread中的MessageQueue中。这两步就是在
    IntentService 创建时的执行操作。

@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();//开启线程

    mServiceLooper = thread.getLooper();//拿到thread 绑定的 Looper 对象
    mServiceHandler = new ServiceHandler(mServiceLooper); //根据 Looper 创建 ServiceHandler 对象。
}
  • HandlerThread#run()

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
  • IntentService#onStart()

    服务创建之后就会去执行onStartCommand()方法,该方法会去调用onStart()方法。该方法接收到意图之后,将其包装成一个Message对象,然后发送到HandlerThread
    对应的消息队列中,这样 ServiceHandler
    将意图传递给onHandleIntent。浏览源码发现该方法是一个空方法,而且是需要子类去实现的。因为是在非
    UI 线程去发送的 Message,因此该方法 handleIntent()
    可以做一些耗时任务。
    注意:onHandleInten方法的Intent参数跟startService的Intent参数是同一个对象。

@Override
public void onStart(Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}
  • mServiceHandler 是如何处理消息的?

    之前在 onStart 方法是通过 mServiceHandler.sendMessage
    的方式发送消息的,因此会在该 Handler 中的 handleMessage
    中去处理消息。在该方法中可以看到它将该 Message 中携带的 Intent
    传入给 onHandleIntent 方法。

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);
    }
}
  • Looper 轮训器已经开启轮训了,那么轮训到的 Message 是怎么通过
    IntentService#ServiceHandler 是处理消息的?

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);//传递当前的id作为当前启动的任务停止服务的标记,不要去调用stopSelf()方法,这样会马上停止服务,有可能其他开启的服务还没执行完毕。
    }
}

ServiceHandler是一个Handler,从onCreate方法可以看出,ServiceHandler是绑定HandlerThread的Looper,也就是说它处于非UI线程,而是跟
HandlerThread 处于同一个线程。当轮训到 Messgae 时,会回调
handleMessage 方法,然后调用 onHandleIntent 将 msg.obj
作为参数传递过去。这个 msg.obj 就是通过 startService 传入的 Intent
对象。

  • 多次启动服务是如何按顺序去执行服务的?

onCreate 方法只会在第一次开启时调用,多次开启服务是不会再次调用
onCreate 方法的,而是会去调用 onStart 方法
,因此 IntentService 中的
HandlerThread
是同一个,也就是所有的任务都会一个线程中去执行。并且会共用一个
ServiceHandler 对象。每次开启任务,都会回调 onStart
方法,然后往消息队列中添加一个任务,但是你注意到在 handleMessage 中处理
完 onHandleIntent 之后会调用 stopSelf(msg.arg1)
这是不是意味着服务就被关闭了呢?其实不是,为什么使用 stopSelf(msg.arg1)
可以参考下面一点。

  • onHandleIntent 执行完毕之后为什么是调用 stopSelf(msg.arg1)而不是
    stopSelf() 呢?

    当onHandleIntent方法执行结束之后,IntentService会通过stopSelf(int
    startId)方法尝试停止服务。这里之所以采用stopSelf(int
    startId)而不是stopSelf()来停止服务,那是因为stopSelf()会立刻停止服务,而这个时候可能还有其他消息未处理,stopSelf(int
    startId)则会等待所有的消息都处理完毕之后才终止服务。一般来说,stopSelf(int
    startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止服务,不相等则不停止服务。

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的特点:

  1. IntentService是借助于消息队列实现的,所以任务的执行顺序就是一个queue的形式;
  2. 由于是单线程(一个工作线程),所以所有的任务需要排队执行;/
  3. 避免了我们再去创建线程和管理service的结束工作;

基于以上,IntentService与Service比较的好处有:

  • 第一,使用方便,代码简洁,不再需要我们自己像Service里面还要去手动创建线程;
  • 第二,当操作完成时,我们不用手动停止Service。

当然,IntentService的缺点也是显而易见:

由于是单个的worker thread,所以任务需要排队,不适合大多数的多任务情况;

二 DEMO实践

DEMO场景描述:

主要由MainActivity和MyIntentService构成,在MainActivity中启动服务,并传递两个参数a和b,在MyIntentService中获取参数,求和,并通过发送广播的形式向UI返回结果,然后MainActivity在接收到广播之后更新UI。

MainActivity.java主要做了三件事:

  1. 注册/注销广播接收器;
  2. 创建UI和更新UI;
  3. 传递参数,启动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()