IntentService详解

一.简介

 

英文解释


IntentService is a base class forServices that handle asynchronous requests (expressed asIntents) on demand. Clients send requests throughstartService(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。

 

 

翻译

IntentService是按需处理异步请求(表示的意图)的服务的基类。客户端通过startservice (Intent)调用发送请求;该服务根据需要启动,使用工作线程依次处理每个意图,并在耗尽工作时停止自身。

 

 

理解

简单说,IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

其实IntentService是专门解决Service中不能进行耗时操作的。

 



 

 

 

 

二.Demo

 

启动式服务

1.服务

package com.example.test.component;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

import androidx.annotation.Nullable;


public class MyIntentService extends IntentService {


    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("MyIntentService","onCreate方法执行Thread----:"+Thread.currentThread().getName());
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        if(intent!=null){
            String name=intent.getStringExtra("name");
            String age=intent.getStringExtra("age");
            Log.i("MyIntentService", "onStartCommand方法中name----:"+name);
            Log.i("MyIntentService", "onStartCommand方法中age----:"+age);
        }
        Log.i("MyIntentService","onStartCommand方法执行Thread----:"+Thread.currentThread().getName());
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            String name=intent.getStringExtra("name");
            String age=intent.getStringExtra("age");
            Log.i("MyIntentService", "onHandleIntent方法中name----:"+name);
            Log.i("MyIntentService", "onHandleIntent方法中age----:"+age);


            //直接进行耗时操作 比如 下载文件 链接网络 下载图片...

            for(int i=0;i<10;i++){
                Log.i("MyIntentService", "onHandleIntent方法中模拟耗时操作i----:"+i);
            }


            Log.i("MyIntentService", "onHandleIntent方法执行Thread----:"+Thread.currentThread().getName());
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("MyIntentService", "onDestroy方法执行Thread----:"+Thread.currentThread().getName());
    }
}

 

注意

<1> 关于构造方法

IntentService的构造方法

public MyIntentService(String name) {
   super(name);
}

报错:
java.lang.RuntimeException: Unable to instantiate service com.finddreams.runningman.MyIntentService: java.lang.InstantiationException: can't instantiate class com.finddreams.runningman.MyIntentService; no empty constructor

 

IntentService的构造方法

public MyIntentService() {
   super("MyIntentService");
}

正确

<2> 系统创建IntentService,默认只创建构造方法和onHandleIntent方法。其他方法均未重写,切手动重写时均显示已过期的标识。

 

 

2.注册

<service
    android:name=".component.MyIntentService"
    android:exported="false">
</service>

 

 

3.启动

Intent intent=new Intent(IntentServiceActivity.this,MyIntentService.class);
intent.putExtra("name", "张三");
intent.putExtra("age", "18");
startService(intent);

 

 

4.结果

点击一次开启

I/MyIntentService: onCreate方法执行Thread----:main

I/MyIntentService: onStartCommand方法中name----:张三

I/MyIntentService: onStartCommand方法中age----:18

I/MyIntentService: onStartCommand方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中name----:张三

I/MyIntentService: onHandleIntent方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9

I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]

I/MyIntentService: onDestroy方法执行Thread----:main

 

点击两次开启

I/MyIntentService: onCreate方法执行Thread----:main

I/MyIntentService: onStartCommand方法中name----:张三

I/MyIntentService: onStartCommand方法中age----:18

I/MyIntentService: onStartCommand方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中name----:张三

I/MyIntentService: onHandleIntent方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9

I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]

I/MyIntentService: onDestroy方法执行Thread----:main





I/MyIntentService: onCreate方法执行Thread----:main

I/MyIntentService: onStartCommand方法中name----:张三

I/MyIntentService: onStartCommand方法中age----:18

I/MyIntentService: onStartCommand方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中name----:张三

I/MyIntentService: onHandleIntent方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9

I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]

I/MyIntentService: onDestroy方法执行Thread----:main


 

5.说明

<1> 通过以上的输出结果我们可以发现,MyIntentService的onCreate、onStartCommand、onDestroy等回调方法都是运行在主线程中的,而onHandleIntent是运行在工作线程IntentService[MyIntentService]中的,这验证了我们上面所说的IntentService的第一个和第二个特点。即只有onHandleIntent方法运行在子线程中,其他生命周期方法和构造方法运行在UI线程。


<2> 如果我们连续调用了多次startService(intent)之后,onStartCommand依次被调用了多次,然后依次执行了onHandleIntent多次,这样就依次完成了job,当最后一个job完成,也就是在最后一次onHandleIntent调用完成之后,整个IntentService的工作都完成,执行onDestroy回调方法,IntentService销毁。

 

 

 

 

 

绑定式服务

1.服务

package com.example.test.component;

import android.app.IntentService;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;


public class MyIntentService extends IntentService {


    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("MyIntentService","onCreate方法执行Thread----:"+Thread.currentThread().getName());
    }


    @Override
    public IBinder onBind(Intent intent) {
        if(intent!=null){
            String name=intent.getStringExtra("name");
            String age=intent.getStringExtra("age");
            Log.i("MyIntentService", "onBind方法中name----:"+name);
            Log.i("MyIntentService", "onBind方法中age----:"+age);
        }
        Log.i("MyIntentService","onBind方法执行Thread----:"+Thread.currentThread().getName());
        return new MyBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("MyIntentService","onUnbind方法执行Thread----:"+Thread.currentThread().getName());
        return super.onUnbind(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            String name=intent.getStringExtra("name");
            String age=intent.getStringExtra("age");
            Log.i("MyIntentService", "onHandleIntent方法中name----:"+name);
            Log.i("MyIntentService", "onHandleIntent方法中age----:"+age);


            //直接进行耗时操作 比如 下载文件 链接网络 下载图片...

            for(int i=0;i<10;i++){
                Log.i("MyIntentService", "onHandleIntent方法中模拟耗时操作i----:"+i);
            }


            Log.i("MyIntentService", "onHandleIntent方法执行Thread----:"+Thread.currentThread().getName());
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("MyIntentService", "onDestroy方法执行Thread----:"+Thread.currentThread().getName());
    }

    /**
     * 代理类
     */

    class MyBinder extends Binder {

        public String testMethod1() {
            return "绑定的服务返回给调用者的回调";
        }

        public int testMethod2() {
            return 20;
        }

        public void testMethod3() {
            Log.d("MyIntentService", "绑定者调用了服务的testMethod3()方法");
        }
    }

}

 

2.绑定

package com.example.test.component;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.example.test.R;

public class IntentServiceActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intentservice);


        TextView textView=findViewById(R.id.activity_intentservice_textview);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent bindIntent=new Intent(IntentServiceActivity.this, MyIntentService.class);
                bindIntent.putExtra("name", "张三");
                bindIntent.putExtra("age", "18");
                startService(bindIntent);
                bindService(bindIntent, MyServiceConnection, BIND_AUTO_CREATE);
            }
        });

    }

    /**
     * ServiceConnection 接口实现类
     */

    ServiceConnection MyServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //获取绑定式服务的代理类
            MyIntentService.MyBinder binder = (MyIntentService.MyBinder) service;
            //调用绑定式服务的各种方法
            String s = binder.testMethod1();
            int n = binder.testMethod2();
            binder.testMethod3();
            Log.i("MyIntentService", "onServiceConnected方法name----:" + name);
            Log.i("MyIntentService", "绑定者获取服务的s----:" + s);
            Log.i("MyIntentService", "绑定者获取服务的n----:" + n);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("MyIntentService", "onServiceDisconnected方法name----:" + name);
        }
    };

}

 

 

3.结果

绑定一次


I/MyIntentService: onCreate方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中name----:张三

I/MyIntentService: onHandleIntent方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1

I/MyIntentService: onBind方法中name----:张三

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2

I/MyIntentService: onBind方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4

I/MyIntentService: onBind方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9

I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]

I/MyIntentService: onServiceConnected方法name----:ComponentInfo{com.example.test/com.example.test.component.MyIntentService}

I/MyIntentService: 绑定者获取服务的s----:绑定的服务返回给调用者的回调

I/MyIntentService: 绑定者获取服务的n----:20

 

绑定两次

I/MyIntentService: onCreate方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中name----:张三

I/MyIntentService: onHandleIntent方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4

I/MyIntentService: onBind方法中name----:张三

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6

I/MyIntentService: onBind方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8

I/MyIntentService: onBind方法执行Thread----:main

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9

I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]

I/MyIntentService: onServiceConnected方法name----:ComponentInfo{com.example.test/com.example.test.component.MyIntentService}

I/MyIntentService: 绑定者获取服务的s----:绑定的服务返回给调用者的回调

I/MyIntentService: 绑定者获取服务的n----:20




I/MyIntentService: onHandleIntent方法中name----:张三

I/MyIntentService: onHandleIntent方法中age----:18

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:0

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:1

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:2

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:3

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:4

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:5

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:6

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:7

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:8

I/MyIntentService: onHandleIntent方法中模拟耗时操作i----:9

I/MyIntentService: onHandleIntent方法执行Thread----:IntentService[MyIntentService]

 

退出APP

I/MyIntentService: onUnbind方法执行Thread----:main

I/MyIntentService: onDestroy方法执行Thread----:main

 

4.说明

绑定式服务onHandleIntent方法执行完成后,没有自动释放,退出页面或者APP时才调用。

 

 

 

 

 

 

 

三.源码


在上面我们已经介绍了IntentService的特点以及如何使用,那么你可能会疑问Android是如何将调度这些intent将其传入onHandleIntent完成工作的呢。

其实IntentService的工作原理很简单,将intent转换为Message并放到消息队列中,然后让Handler依次从中取出Message对其进行处理
 


 

IntentService的源码

package android.app;
 
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
 
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,确保onHandleIntent不会阻塞主线程
   onHandleIntent((Intent)msg.obj);
   //在执行完了onHandleIntent之后,我们需要调用stopSelf(startId)声明某个job完成了
   //当所有job完成的时候,Android就会回调onDestroy方法,销毁IntentService
   stopSelf(msg.arg1);
  }
 }
 

 public IntentService(String name) {
  //此处的name将用作线程名称
  super(); 
  mName = name;
 }
 

 public void setIntentRedelivery(boolean enabled) {
  mRedelivery = enabled;
 }
 

 @Override
 public void onCreate() {
  super.onCreate();
  //创建HandlerThread,利用mName作为线程名称,HandlerThread是IntentService的工作线程
  HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
  thread.start();
  mServiceLooper = thread.getLooper();
  //将创建的HandlerThread所绑定的looper对象传递给ServiceHandler,
  //这样我们创建的Handler就和HandlerThread通过消息队列绑定在了一起
  mServiceHandler = new ServiceHandler(mServiceLooper);
 }

 
 @Override
 public void onStart(Intent intent, int startId) {
  //在此方法中创建Message对象,并将intent作为Message的obj参数,
  //这样Message与Intent就关联起来了
  Message msg = mServiceHandler.obtainMessage();
  msg.arg1 = startId;
  msg.obj = intent;
  //将关联了Intent信息的Message发送给Handler
  mServiceHandler.sendMessage(msg);
 }

 
 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  //IntentService重写了onStartCommand回调方法:在内部调用onStart回调方法
  //所以我们在继承IntentService时,不应该再覆写该方法,即便覆盖该方法,我们也应该调用super.onStartCommand()
  onStart(intent, startId);
  return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
 }
 

 @Override
 public void onDestroy() {
  //在onDestroy方法中调用了Handler的quit方法,该方法会终止消息循环
  mServiceLooper.quit();
 }

 
 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }
 
 protected abstract void onHandleIntent(Intent intent);

}


IntentService继承自Service类,并且IntentService重写了onCreate、onStartCommand、onStart、onDestroy回调方法,并且IntentService还添加了一个onHandleIntent回调方法。

 

1.onCreate方法

   在onCreate回调方法中,利用mName作为线程名称,创建HandlerThread,HandlerThread是IntentService的工作线程。HandlerThread在执行了start方法之后,其本身就关联了消息队列和Looper,并且消息队列开始循环起来。


 

2.onStartCommand方法

   IntentService重写了onStartCommand回调方法,在内部调用onStart回调方法。


 

3.onStart方法

   在onStart方法中创建Message对象,并将intent作为Message的obj参数,这样Message与Intent就关联起来了。然后通过Handler的sendMessage方法将关联了Intent信息的Message发送给Handler。


 

4.onHandleIntent方法

   当在onStart方法中,通过sendMessage方法将Message放入到Handler所关联的消息队列中后,Handler所关联的Looper对象会从消息队列中取出一个Message,然后将其传入Handler的handleMessage方法中。

   在handleMessage方法中首先通过Message的obj获取到了原始的Intent对象,然后将其作为参数传给了onHandleIntent方法让其执行。

   handleMessage方法是运行在HandlerThread的,所以onHandleIntent也是运行在工作线程中的。在执行完了onHandleIntent之后,我们需要调用stopSelf(startId)声明某个job完成了。当所有job完成的时候,Android就会回调onDestroy方法,销毁IntentService。

 

 

5.onDestroy方法

   当所有job完成的时候,Service会销毁并执行其onDestroy回调方法。在该方法中,调用了Handler的quit方法,该方法会终止消息循环。

 

 

6.总结

   IntentService可以在工作线程中完成工作而不阻塞主线程,但是IntentService不能并行处理多个job,只能依次处理,一个接一个,当所有的job完成后,会自动执行onDestroy方法而无需我们自己调用stopSelf()或stopSelf(startId)方法。IntentService和Service去了这样的差别之外,就没有什么区别了,比如注册一样,启动方式一样(启动式 绑定式)等等。

   当我们通过startService多次启动了IntentService,这会产生多个job,由于IntentService只持有一个工作线程,所以每次onHandleIntent只能处理一个job。面对多个job,IntentService会如何处理?处理方式是one-by-one,也就是一个一个按照先后顺序处理,先将intent1传入onHandleIntent,让其完成job1,然后将intent2传入onHandleIntent,让其完成job2…这样直至所有job完成,所以我们IntentService不能并行的执行多个job,只能一个一个的按照先后顺序完成,当所有job完成的时候IntentService就销毁了,会执行onDestroy回调方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值