Android IntentService详解(源码分析)

目录: java

目录

1. 前言

本文是对 IntentService 的深刻学习,包含其基本使用方法、IntentService更新处理UI工做,以及对 IntentService 的源码分析。android

1.1 定义

IntentService 是 Service 的子类,继承于 Service 类,用于处理后台异步请求任务。异步

用户经过调用 Context.StartService(Intent) 发送请求,服务根据请求启动,使用工做线程依次处理每一个 Intent任务请求,并在处理完全部任务请求后自身中止服务。ide

使用时,扩展 IntentService ,即实现它的子类并具体实现 onHandleIntent(android.content.Intent) 方法。IntentService 接收 Intent,启动工做线程,并在适当时机中止服务。函数

全部的请求都在同一个工做线程上处理,一次处理一个请求,因此处理完因此的请求可能会花费很长的时间,但因为 IntentService 是另外建立的线程来工做,因此保证不会阻止App 的主线程,防止 App 出现 ANR。oop

1.2 使用场景

用于处理后台长时间的耗时操做,如:下载文件、播放音乐...源码分析

2. 使用方法

因为 IntentService 是抽象类,因此在实际使用中,咱们须要建立一个 IntentService 子类来具体实现。学习

使用步骤分为两步:ui

  1. 建立 IntentService 子类,并在清单文件中注册
  2. 在 Activity 中经过调用 startService(Intent) 方法发送任务请求。

例子: 咱们模拟在后台进行下载以及读取文件的耗时操做,观察打印出来的 Log 信息。this

以下所示:

MyIntentService处理耗时操做的日志信息
IntentService 的执行流程为:onCreate() -> onStartCommand() -> onStart() -> onHandleIntent -> ···处理完全部请求··· -> onDestroy()

具体代码以下所示:分 Java & Kotlin 两个版本展现。

2.1 Java版本

步骤一:建立 MyIntentService

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";
    public static final String DOWNLOAD_ACTION = "DOWNLOAD_ACTION";
    public static final String READ_ACTION = "READ_ACTION";
    public static final String TEST_AUTHOR = "TEST_AUTHOR";

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

    /** * 进行一些耗时操做 * @param intent 经过startService(Intent intent)方法传入 */
    @Override
    protected void onHandleIntent(Intent intent) {
        Log.e(TAG, "onHandleIntent: ");
        if (intent != null) {
            final String action = intent.getAction();
            String author = intent.getExtras().getString(TEST_AUTHOR);
            //模拟下载动做
            if (DOWNLOAD_ACTION.equals(action)) {
                for (int i = 0; i < 5; i++) {
                    try {
                        //线程等待1s,模拟耗时操做
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e(TAG, author + " " + action + " " + i);
                }
            }
            //模拟读操做
            if (READ_ACTION.equals(action)) {
                for (int i = 0; i < 5; i++) {
                    try {
                        //线程等待2s,模拟耗时操做
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e(TAG, author + " " + action + " " + i);
                }
            }
        }

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onCreate: ");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.e(TAG, "onStart: ");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: ");
        Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
    }
}
复制代码

并记得在清单文件中注册,这一步你也能够经过 Android Studio 来帮咱们完成

<service android:name=".intentservice.MyIntentService" android:exported="false">
</service>
复制代码

步骤二:经过 startService(Intent) 发送任务请求

public class IntentServiceActivity extends AppCompatActivity {

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

        //模拟 Jere 作下载动做
        Intent intent = new Intent(this, MyIntentService.class);
        intent.setAction(MyIntentService.DOWNLOAD_ACTION);
        intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere");
        startService(intent);

        //模拟 James 作读取动做
        Intent jamesIntent = new Intent(this, MyIntentService.class);
        jamesIntent.setAction(MyIntentService.READ_ACTION);
        jamesIntent.putExtra(MyIntentService.TEST_AUTHOR, "James");
        startService(jamesIntent);
    }
}
复制代码

2.2 Koltin版本

步骤一:建立 MyIntentService

class MyIntentService : IntentService("MyIntentService") {
    companion object {
        private val TAG: String = "MyIntentService"
        val DOWNLOAD_ACTION = "DOWNLOAD_ACTION"
        val READ_ACTION = "READ_ACTION"
        val TEST_AUTHOR = "TEST_AUTHOR"
    }


    override fun onHandleIntent(intent: Intent?) {
        val action: String? = intent?.action
        val author: String? = intent?.extras?.getString(TEST_AUTHOR)

        when (intent?.action) {
            DOWNLOAD_ACTION -> {
                for (i in 0..10) {
                    Thread.sleep(1000)
                    Log.e(TAG, "$author $action $i")
                }
            }
            READ_ACTION -> {
                for (j in 0..10) {
                    Thread.sleep(2000)
                    Log.e(TAG, "$author $action $j")
                }
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        Log.e(TAG, "onCreate")
        Toast.makeText(this, "conCreate", Toast.LENGTH_SHORT).show()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e(TAG, "onStartCommand")
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show()
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.e(TAG, "onDestroy")
        Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show()
    }
}
复制代码

在清单文件中注册:

<service android:name=".multiplethread.intentservice.MyIntentService" android:exported="false">
</service>
复制代码

步骤二:经过 startService(Intent) 发送任务请求

class TestIntentServiceActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_intent_service)

        val intent = Intent()
        intent.setClass(this, MyIntentService::class.java)
        intent.action = MyIntentService.DOWNLOAD_ACTION
        intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere")
        startService(intent)

        val jamesIntent = Intent()
        jamesIntent.setClass(this, MyIntentService::class.java)
        jamesIntent.action = MyIntentService.READ_ACTION
        jamesIntent.putExtra(MyIntentService.TEST_AUTHOR, "James")
        startService(jamesIntent)
    }
}
复制代码

2.3 IntentService更新处理UI工做

思考: 在上面的例子中,咱们是经过在打印出来的日志信息来观察后台异步任务的执行状况,那 IntentService 能够处理 UI 工做吗?

答: IntentService 是服务端,确定是不能够处理 UI 工做的,可是他能够经过其对应的客户端,也就是 Activity 来更新处理 UI 工做。

客户端与服务端之间的通讯
客户端与服务端之间的通讯,咱们使用 Messenger , 关于 Messenger 内容请看另外一篇博客 Android Messenger初探,具体实现以下所示:

例子: 咱们在 IntentService 模拟下载任务,经过 ProgressBar 显示下载进度。

效果图以下所示:

IntentService更新处理UI工做
具体代码以下所示:分Java & Kotlin 两个版本展现。

2.3.1 Java版本

  1. 在 Activity 中发送请求时,新建一个 Messenger 对象,传递给 IntentService。
public class IntentServiceActivity extends AppCompatActivity {
    private ProgressBar downloadProgressBar;

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

        downloadProgressBar = findViewById(R.id.download_progress_bar);

        //用于建立 Messenger,接收 IntentService 回复的消息
        MessengerHandler messengerHandler = new MessengerHandler(this);

        //模拟 Jere 作下载动做
        Intent intent = new Intent(this, MyIntentService.class);
        intent.setAction(MyIntentService.DOWNLOAD_ACTION);
        intent.putExtra(MyIntentService.TEST_AUTHOR, "Jere");
        //将 Messenger 传递给 IntentService,让其回复消息回来
        intent.putExtra(MyIntentService.TEST_MESSENGER, new Messenger(messengerHandler));
        startService(intent);
    }

    /** * 用于建立 Messenger 对象 * * 静态内部类,防止内存泄漏 */
    public static class MessengerHandler extends Handler {
        private WeakReference<IntentServiceActivity> weakReference;

        MessengerHandler(IntentServiceActivity activity) {
            weakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //msg 为 IntentService 回复的消息,包含 Bundle 等信息。
            Bundle bundle = msg.getData();
            //获取 IntentService 传递过来的 下载进度 参数
            int downloadProgressBarValue = bundle.getInt(MyIntentService.DOWNLOAD_PROGRESS_VALUE_KEY);

            //将下载进度设置成 ProgressBar 的进度,显示出来。
            IntentServiceActivity activity = weakReference.get();
            if (activity != null && !activity.isFinishing()) {
                activity.downloadProgressBar.setProgress(downloadProgressBarValue);
            }

        }
    }

}
复制代码
  1. 在 IntentService 中获取 Messenger 对象,并回复消息给 Activity。
public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";
    public static final String DOWNLOAD_ACTION = "DOWNLOAD_ACTION";
    public static final String READ_ACTION = "READ_ACTION";
    public static final String TEST_AUTHOR = "TEST_AUTHOR";
    public static final String TEST_MESSENGER = "TEST_MESSENGER";
    public static final String DOWNLOAD_PROGRESS_VALUE_KEY = "DOWNLOAD_PROGRESS_VALUE";

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

    /** * 进行一些耗时操做 * @param intent 经过startService(Intent intent)方法传入 */
    @Override
    protected void onHandleIntent(Intent intent) {
        Log.e(TAG, "onHandleIntent: ");
        if (intent != null) {
            final String action = intent.getAction();
            String author = intent.getExtras().getString(TEST_AUTHOR);

            //模拟下载动做
            if (DOWNLOAD_ACTION.equals(action)) {
                for (int i = 0; i <= 6; i++) {
                    try {
                        //线程等待1s,模拟耗时操做
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e(TAG, author + " " + action + " " + i);
                    //获取从 Activity 传入的 Messenger
                    Messenger messenger = (Messenger) intent.getExtras().get(TEST_MESSENGER);
                    //新建消息,设置下载进度参数
                    Message msg = new Message();
                    Bundle bundle = new Bundle();
                    bundle.putInt(DOWNLOAD_PROGRESS_VALUE_KEY, i);
                    msg.setData(bundle);
                    try {
                        //回复消息
                        messenger.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onCreate: ");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        super.onStart(intent, startId);
        Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onStart: ");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: ");
        Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
    }

}
复制代码

这样就实现了 IntentService 更新处理 UI 工做,具体效果看上图 IntentService更新处理UI工做

2.3.2 Kotlin版本

一样,Kotlin的实现方式为:

  1. 在 Activity 中发送请求时,新建一个 Messenger 对象,传递给 IntentService。
class TestIntentServiceActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_intent_service)

        val intent = Intent()
        intent.setClass(this, MyIntentService::class.java)
        intent.action = MyIntentService.DOWNLOAD_ACTION_KEY
        intent.putExtra(MyIntentService.TEST_AUTHOR_KEY, "Jere")
        //将 Messenger 传递给 IntentService, 使其传递消息回来,实现客户端与服务端之间进行沟通
        intent.putExtra(MyIntentService.TEST_MESSENGER_KEY, Messenger(MessengerHandler(this)))
        startService(intent)
    }

    /** * 此 Handler 用于建立 Messenger 对象,接收 IntentService 回复回来的消息 * * 静态内部类,防止内存泄漏 */
    class MessengerHandler(activity: TestIntentServiceActivity) : Handler() {
        var weakReference: WeakReference<TestIntentServiceActivity> = WeakReference(activity)

        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            //msg 为 IntentService 回复的消息,包含 Bundle 等信息。
            val bundle: Bundle = msg.data
            //获取 IntentService 传递过来的 下载进度 参数
            val downloadProgressBarValue: Int =
                bundle.get(MyIntentService.DOWNLOAD_PROGRESS_BAR_VALUE_KEY) as Int
            val activity: TestIntentServiceActivity? = weakReference.get()
            //将下载进度设置成 ProgressBar 的进度,显示出来。
            if (activity != null && !activity.isFinishing) {
                activity.intentServiceDownloadProgressBar.progress = downloadProgressBarValue
            }
        }
    }
}
复制代码
  1. 在 IntentService 中获取 Messenger 对象,并回复消息给 Activity。
class MyIntentService : IntentService("MyIntentService") {
    companion object {
        private val TAG: String = "MyIntentService"
        val DOWNLOAD_ACTION_KEY = "DOWNLOAD_ACTION"
        val READ_ACTION_KEY = "READ_ACTION"
        val TEST_AUTHOR_KEY = "TEST_AUTHOR"
        val TEST_MESSENGER_KEY = "TEST_MESSENGER"
        val DOWNLOAD_PROGRESS_BAR_VALUE_KEY = "DOWNLOAD_PROGRESS_BAR_VALUE"
    }

    override fun onHandleIntent(intent: Intent?) {
        val action: String? = intent?.action
        val author: String? = intent?.extras?.getString(TEST_AUTHOR_KEY)

        when (intent?.action) {
            DOWNLOAD_ACTION_KEY -> {
                for (i in 0..6) {
                    Thread.sleep(1000)
                    Log.e(TAG, "$author $action $i")
                    //获取从 Activity 中传入的 Messenger 对象
                    val messenger: Messenger = intent.extras?.get(TEST_MESSENGER_KEY) as Messenger
                    //新建一个 Message 对象
                    val msg: Message = Message()
                    //为 Message 对象设置 下载进度 参数
                    val bundle: Bundle = Bundle()
                    bundle.putInt(DOWNLOAD_PROGRESS_BAR_VALUE_KEY, i)
                    msg.data = bundle
                    //Messenger 回复消息给 Activity
                    messenger.send(msg)
                }
            }
            READ_ACTION_KEY -> {
                for (j in 0..10) {
                    Thread.sleep(2000)
                    Log.e(TAG, "$author $action $j")
                }
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        Log.e(TAG, "onCreate")
        Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e(TAG, "onStartCommand")
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show()
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onStart(intent: Intent?, startId: Int) {
        super.onStart(intent, startId)
        Log.e(TAG, "onStart")
        Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.e(TAG, "onDestroy")
        Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show()
    }
}
复制代码

具体效果看上图 IntentService更新处理UI工做

3. 源码分析

上面介绍了 IntentService 的使用方法,接下来,咱们来看一下 IntentService 的源码。若是你理解了 Hander、Looper、MessageQueue三者之间的关系,那么理解 IntentService 的源代码十分容易。(若是不理解,请看博客 Android Handler深刻学习(源码分析)

根据上面的例子,咱们知道了 IntentService 的执行顺序为:

onCreate() -> onStartCommand() -> onStart() -> onHandleIntent -> ···处理完全部请求··· -> onDestroy()

IntentService 源码以下:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    //建立一个内部类,继承于 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);
        }
    }

    /** * IntentService 构造函数,在你的子类构造函数中调用(在子类中经过 super(name) 方法调用) * * @param 参数 name 用于命名工做线程 * */
    public IntentService(String name) {
        super();
        mName = name;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //建立一个 HandlerThread 对象
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        //启动 HandlerThread 线程
        thread.start();
        //获取 HandlerThread 中建立的 Looper 对象,赋值给全局变量 mServiceLooper。
        mServiceLooper = thread.getLooper();
        //建立一个 Handler 对象,并关联刚刚经过 HandlerThread 建立的 Looper 对象,即关联 mServiceLooper
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        //发送消息给 mServiceHanlder,
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /** * 你不该该在你的 IntentService 类中复写 onStartCommand() 方法。 * 相反,你应该复写 onHandleIntent() 方法,该方法会在 IntentService 接收到启动请求时被调用。 */
    @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() {
        //退出 Looper 消息循环
        mServiceLooper.quit();
    }

    /** * 除非是绑定服务,不然你不须要实现此方法,由于此方法的默认实现返回 null. */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    /** * 此方法在工做线程中被调用用于处理请求,一次只能处理一个请求,处理工做运行于独立于其余应用程序的工做线程中。 * 所以,若是该段代码花费了很长的一段时间,它会阻塞同一个 IntentService 的其余请求,但不会阻塞其余任何东西。 * 当全部的请求都被处理完,该 IntentService 就会中止运行,因此你不用调用 stopSelf() 方法。 * * @param intent 经过 startService(Intent) 方法传入。若是服务在其进程消失后从新启动,则此值可能为空; */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}
复制代码

总结:

  1. 在 onCreate() 方法中,咱们新建一个 HandlerThread 对象,而后启用它,获取其建立的 Looper 对象,而后新建立一个 Looper 对象关联该 Looper 对象。关于 HandlerThread 的知识点请看另外一篇博客 Android HandlerThread详解(源码分析)
  2. 而后咱们在 onStart() 方法中,经过 Message,将 Intent任务请求 发送给 mServiceHandler,Intent任务请求就是咱们在 Activity 中经过 startService(Intent) 传入的 Intent。
  3. mServiceHanlder 接受到任务请求,调用 onHandleIntent() 方法处理任务请求,处理完全部请求后,调用 stopSelf() 结束 IntentService。

至此 HandlerThread 的源码也就分析结束了。 其实分享文章的最大目的正是等待着有人指出个人错误,若是你发现哪里有错误,请毫无保留的指出便可,虚心请教。

另外,若是你以为文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!

相关文章
相关标签/搜索