首页 > 系统 > Android > 正文

Android IntentService源码解析

2019-11-06 09:55:04
字体:
来源:转载
供稿:网友

IntentService,是Service类的一个子类。同时,IntentService是一个抽象类,所以要想使用它必须要通过实现一个子类来使用它。

IntentService不同于普通Service的是: 1. 在IntentService中会默认创建一个子线程用于执行传递的Intent,这样在执行耗时操作时不需要手动去创建线程了 2. 在IntentService中创建工作队列,用于将 Intent 逐一传递给 onHandleIntent() 实现,这样就永远不必担心多线程问题。 3. 在处理完所有启动请求后停止服务,因此您永远不必调用 stopSelf()。

IntentService的简单使用

首先,创建一个类继承自IntentService

package com.zhangke.intentservicedemo;import android.app.IntentService;import android.content.Context;import android.content.Intent;import android.os.SystemClock;import android.util.Log;/** * */public class DownloadService extends IntentService { PRivate static final String TAG = "zhangke"; private static final String DOWN_URL = "down_url"; public DownloadService() { super("DownloadService"); } @Override protected void onHandleIntent(Intent intent) { if (intent == null) { return; } String url = intent.getStringExtra(DOWN_URL); downlaod(url); } /** * 模拟下载任务 * @param url */ private void downlaod(String url) { Log.e(TAG, "url = " + url +" 正在下载中..."); SystemClock.sleep(3000); } public static void startDownload(Context context, String url) { Intent intent = new Intent(context, DownloadService.class); intent.putExtra(DOWN_URL, url); context.startService(intent); }}

在activity中使用DownloadService

package com.zhangke.intentservicedemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public int id = 0; public void startDownload(View view) { DownloadService.startDownload(this, "url" + id ++); }}

布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.zhangke.intentservicedemo.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="startDownload" android:text="开始下载任务" /></LinearLayout>

没当我们通过button点击一次,IntentServie就会被执行一次,如果一次性多点击几次,程序也次执行IntentService,并且多个任务是顺序执行的。

02-27 02:47:24.606 1883-1922/com.zhangke.intentservicedemo E/zhangke: url = url0 正在下载中...02-27 02:47:30.727 1883-1924/com.zhangke.intentservicedemo E/zhangke: url = url1 正在下载中...02-27 02:47:33.729 1883-1924/com.zhangke.intentservicedemo E/zhangke: url = url2 正在下载中...02-27 02:47:36.730 1883-1924/com.zhangke.intentservicedemo E/zhangke: url = url3 正在下载中...02-27 02:47:39.732 1883-1924/com.zhangke.intentservicedemo E/zhangke: url = url4 正在下载中...02-27 02:47:42.733 1883-1924/com.zhangke.intentservicedemo E/zhangke: url = url5 正在下载中...

IntentService源码分析

HandlerThread介绍

在IntentService中,主要使用到了HandlerThread。HandlerThread是Thread的一个子类,在该类中可以使用Handler。其实HandlerThread的实现原理非常简单,就是在run方法中通过Looper.prepare()来创建消息队列,然后通过Looper.loop()方法开启消息循环,整个实现流程如同ActivityThread.main()方法中MainLooper的初始化过程。

通过在Thread在初始化一个Looper,这样做的好处想必大家都清楚,那就是在Thread中可以使用Handler。

下面看看HandlerThread的run方法的具体实现:

@Overridepublic void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1;}

IntentService源码分析

public abstract class IntentService extends Service { /** * 1、在IntentServcie被首次创建时,会执行onCreate方法 */ @Override public void onCreate() { super.onCreate(); // 1、创建一个HandlerThread,用于接收消息 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); // 2、获取上面HandlerThread的实例的looper mServiceLooper = thread.getLooper(); /* * 3、通过HandlerThread的looper,创建一个handler对象mServiceHandler,这样通过mServiceHandler * 发送的对象都会在HandlerThread中被处理 */ mServiceHandler = new ServiceHandler(mServiceLooper); } /** * 2、每次启动IntentServcie, onStartCommand方法会被调用,该方法内部主要调用onStart方法 */ @Override public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } /** * 3、在onStrat方法中主要是通过mServiceHandler发送了一条消息。 * * 在mServiceHandler发送的消息中,intent对象会作为发送消息的参数(这里的intent和通过startServcie方法传递的intent是同一个对象) * * 同时,消息中会被携带一个startId的参数,该参数主要用于判断服务是否结束 * */ @Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * 4、ServiceHandler,该handler对象是通过HandlerThread的looper创建的,所以通过ServiceHandler * 发送的消息都会被发送到HandlerThread中执行,由于HandlerThread是一个Thread类,这样就实现了在IntentService * 无需创建一个Thread来执行后台耗时任务。 * * 同时,由于ServiceHandler内部的消息队列是通过looper维护的,这样就保证了消息队列是顺序执行的,所以IntentService也是 * 顺序执行任务的。 */ private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { /* * 1、抽象方法,需要在子类中实现具体后台任务的实现 */ onHandleIntent((Intent) msg.obj); /* * 2、在任务执行完成,自动停止服务。 * * msg.arg1 就是在startId,这是为每一消息生成的唯一标识。每通过IntentService处理一个请求时, * 都会有一个消息被放入到消息队列中,只有当最后一个消息执行完成即msg.arg1等于最后一个放入到消息队列的startId, * 服务才会被停止,否者IntentService不会被停止 * * 这样做的好处就是:保证消息队列中的所有消息都被处理,服务才会被停止。 * */ stopSelf(msg.arg1); } } /** * 5、抽象方法,该方法需要在IntentService的子类中实现,也是IntentService中唯一一个需要实现的方法 * @param intent */ protected abstract void onHandleIntent(Intent intent);}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表