IntentService原理

IntentService的Demo程序IntentService常被用于处理异步任务,使用的步骤是,先继承IntentService,再在handleIntent方法里写业务逻辑。handleIntent是在子线程执行的,所以不必担心ANR之类的问题,可以执行IO操作,下载等操作,且当执行完后会自动销毁,很方便。先写一个简单的Demo。CountService.java:publicc…

大家好,又见面了,我是你们的朋友全栈君。

IntentService的Demo程序

IntentService常被用于处理异步任务,使用的步骤是,先继承IntentService,再在handleIntent方法里写业务逻辑。handleIntent是在子线程执行的,所以不必担心ANR之类的问题,可以执行IO操作,下载等操作,且当执行完后会自动销毁,很方便。
先写一个简单的Demo。
CountService.java:

public class CountService extends IntentService {

    public final static String EXTRA_NUMBER = "extra_number";
    public String TAG = CountService.class.getSimpleName();

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

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    Log.e(TAG,"onStartCommand -->> startId : "+startId);
    return super.onStartCommand(intent, flags, startId);
}

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
// 通过intent来接收传递过来的数据,这里运行的线程为子线程,执行完后,这个Service就会销毁
        int count = intent.getIntExtra(EXTRA_NUMBER, 1);
        for (int i = 0 ; i < count ; i++ ){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.e(TAG,"onHandleIntent --> counting "+i);
        }
        Log.e(TAG,"onHandleIntent count end");
    }

@Override
public void onDestroy() {
    super.onDestroy();
    Log.e(TAG,"onDestroy");
}

}

CountActivity.java:

public class CountActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 这个例子中布局什么的无所谓
        setContentView(R.layout.activity_test);

        Intent intent = new Intent(this,CountService.class);
        intent.putExtra(CountService.EXTRA_NUMBER,10);
        startService(intent);

        Intent intent2 = new Intent(this,CountService.class);
        intent2.putExtra(CountService.EXTRA_NUMBER,5);
        startService(intent2);

    }
}

当我们执行完后查看log信息:
在这里插入图片描述
分析一下这个log信息,在发送两个任务过去后,发现onStartCommand方法先执行,之后一个任务执行完后(onHandleIntent count end),再执行下一个任务,所有任务执行完后,这个Service就被销毁了(onDestroy)。

Demo的运行情况就讲到这里,下面我们通过源码,来揭开IntentService的神秘面纱。

源码分析

IntentService继承于Service,是一个抽象类。代码量不太多,只有180行左右,所以读起来也不是特别复杂。
在这里插入图片描述
先看IntentService的成员变量:

  1. String mName ; 这是IntentService所在线程的名字,可在声明一个IntentService的时候,用IntentService的构造方法 IntentService(String name)从外部传入进来。
  2. boolean mRedelivery; Redelivery是重发的意思,看一看与该成员变量有关的方法 setIntentRedelivery(boolean enable):
/**
 * Sets intent redelivery preferences.  Usually called from the constructor
 * with your preferred semantics.
 *
 * <p>If enabled is true,
 * {@link #onStartCommand(Intent, int, int)} will return
 * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
 * {@link #onHandleIntent(Intent)} returns, the process will be restarted
 * and the intent redelivered.  If multiple Intents have been sent, only
 * the most recent one is guaranteed to be redelivered.
 *
 * <p>If enabled is false (the default),
 * {@link #onStartCommand(Intent, int, int)} will return
 * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
 * dies along with it.
 */
public void setIntentRedelivery(boolean enabled) {
    mRedelivery = enabled;
}

大致意思是设置重发的偏好。
如果为true, onStartCommand()方法会返回START_REDELIVER_INTENT,所以这个进程如果在onHandleIntent()没有执行的时候死亡,这个进程会重新开启并且intent会重新传输。如果多个Intent已经被发出,只有最近的那个能保证被重新传输。
如果为false,onStartCommand()方法会返回START_NOT_STICKY,如果进程死了,那么这个Intent也随着一起死了。

  1. ServiceHandler mServiceHandler;
    ServiceHandler 是IntentService的内部类,继承于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);
    }
} 

重点来了 ,在handleMessage()方法中,我们看到了 onHandleIntent() 这个方法,这不就是执行异步任务的那个需要重写的方法吗?执行完onHanderIntent()后,就执行stopSelf(),所以IntentService就被销毁了。

  1. Looper mServiceLooper; 这个Looper是实例化ServiceHandler时传递进去的Looper,这个Looper是子线程的。这个Looper在onCreate()方法里面被实例化。

接下来再来看它的方法,我们将通过方法将IntentService的工作流程和它的成员变量串连起来。

  1. onCreate()方法:
@Override
public void onCreate() {
    // TODO: It would be nice to have an option to hold a partial wakelock
    // during processing, and to have a static startService(Context, Intent)
    // method that would launch the service & hand off a wakelock.

    super.onCreate();
    // HandlerThread继承于Thread,可见这是一个子线程
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    // HandlerThread里面的Looper,那就是说这个mServiceLooper是子线程的Looper
    mServiceLooper = thread.getLooper();
    // 传入了子线程的Looper--mServiceLooper来实例化ServiceHandler,ServiceHandler的handleMessage方法是在子线程中进行的
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

由于IntentService继承于Service,所以也同样有一样的生命周期。当实例化了一个IntentService后,后走onCreate()、onStart(),当用Intent开启一个Service时,会调用onStartCommand()。由于这里的HandlerThread是Thread的子类,它的Looper是子线程的Looper,这样ServiceHandler的构造方法传入的是子线程的Looper,所以ServerHandler的handlerMessage()方法是在子线程中进行的。

  1. onStart()方法:
@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

在这里intent对象和id,被装进Message对象中,然后发送到ServiceHandler对象中。前面已经提到IntentService里面的ServiceHandler的handleMessage():

 public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);	// 执行完后就停止服务	
    }

从这里调用到了onHandleIntent()方法,从而执行到重写的onHandleIntent()的代码。

  1. onStartCommand()方法:
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

Service类从这里接收到Intent对象,然后调用onStart()方法,就执行到了onHandleIntent()的代码。
来回顾一下下面的代码:

        Intent intent = new Intent(this,CountService.class);
        intent.putExtra(CountService.EXTRA_NUMBER,10);
        startService(intent);

当这段代码被执行,CountService会被实例化,走生命周期的 onCreate()方法,创建 HandlerThread对象,创建在子线程中执行的ServiceHandler,调用了startService(intent)则会执行到onStartCommand()方法,再调用onStart()方法,把intent对象通过Message传递到handleIntent()方法中。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125828.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • DelphiXE7取代默认的ActionList编辑器

    DelphiXE7取代默认的ActionList编辑器DelphiXE7取代默认的ActionList编辑器。其他XE版本应该可以用。Delphi5或7需要修改代码。默认的编辑器只能看到Action的名称,不能看到标题,因此做了这个编辑器。增加了以下功能:1、ListView显示Action的标题,图标,快捷键。2、Action自动命名的尾部序号宽度为3位数字。3、快速选择标准Action。4、收藏Action。代码修改自ECont…

  • pycharm怎么进行断点调试_pycharm怎么设置断点调试

    pycharm怎么进行断点调试_pycharm怎么设置断点调试PyCharm作为IDE,断点调试是必须有的功能。否则,我们还真不如用纯编辑器写的快。【运行】和【调试】前的设置,请看文章1.添加断点断点的添加如下图所示在代码前面左键单机即可 2.调试断点点击那个绿色的甲虫图标,进行断点调试。点击后,会运行到第一个断点。会显示该断点之前的变量信息。 点击StepOver或者按F8,我们继续往下运行,到下一个断点,按钮…

  • PreparedStatement的用法「建议收藏」

    PreparedStatement的用法「建议收藏」一、用法:PreparedStatement是Statement的子接口,Statement在使用的过程中,直接拼写SQL是很容易出错的且难用的,PreparedStatement带有模版的思想,减少了出错的机率。1、写sql模版,并和PreparedStatement绑定StringsqlsqlTemplate="insertempVALUE(?,?,?)";Prepar…

  • 你不知道的PreparedStatement预编译[通俗易懂]

    你不知道的PreparedStatement预编译[通俗易懂]大家都知道,Mybatis内置参数,形如#{xxx}的,均采用了sql预编译的形式,大致知道mybatis底层使用PreparedStatement,过程是先将带有占位符(即”?”)的sql模板发送至mysql服务器,由服务器对此无参数的sql进行编译后,将编译结果缓存,然后直接执行带有真实参数的sql。如果你的基本结论也是如此,那你就大错特错了。目录1.mysql是否默认开启了预编译功…

  • 软件测试用例的设计方法_设计测试用例的依据

    软件测试用例的设计方法_设计测试用例的依据测试用例设计方法,等价类划分法,边界值分析法,错误推测法,因果图法,判定表驱动法,三角形问题用例设计

    2022年10月10日
  • mac pycharm安装设置_python爬虫 | mac系统PyCharm的安装「建议收藏」

    mac pycharm安装设置_python爬虫 | mac系统PyCharm的安装「建议收藏」视频在之前我们是不是提到了,后面我们要学一个集成的开发环境,就是IDE。全称IntegratedDevelopmentEnvironment,翻译过来集成开发环境。我们经常用PyCharm作为Python开发的IDE,我们以后所有的代码当中可能就要用这个工具去写了。下载我们直接在百度输入,https://www.jetbrains.com/pycharm,进入pycharm安装界面…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号