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)
blank

相关推荐

  • 并查集类的c++封装,比較union_find algorithm四种实现方法之间的性能区别

    并查集类的c++封装,比較union_find algorithm四种实现方法之间的性能区别

    2021年11月17日
  • 智能算法学习总结

    智能算法学习总结本科的时候学习了智能信息处理这门课程,所使用的教材是《计算智能》张军,詹志辉.计算智能[M].清华大学出版社,2009.11之前回忆了一下一些还有点记忆的算法,写了一点博客如下:1、神经网络的基础知识与简单分类编程https://blog.csdn.net/SweeNeil/article/details/865313842、模糊逻辑基本原理与编程https://…

  • java 异步调用方法_java异步调用方法有哪些?如何实现异步调用?

    java 异步调用方法_java异步调用方法有哪些?如何实现异步调用?你知道java异步调用方法都有哪些吗?下面的文章内容,就对这方面的问题做了一下整理,一起来看看java异步调用的方法吧!1、利用Spring的异步方法去执行注:没有返回值在启动类又或者是配置类加上@EnableAsync注解。packageme.deweixu.aysncdemo;importorg.springframework.boot.SpringApplication;importo…

  • 数据仓库——阿里五层模型架构「建议收藏」

    数据仓库——阿里五层模型架构「建议收藏」目录1.ODS数据准备层2.DWD数据明细层3.DW(B/S)数据汇总层4.DM数据集市层5.ST数据应用层解码OneData,阿里的数仓之路1.ODS数据准备层

  • 8000401a 因为配置标志不正确 错误及解决办法

    8000401a 因为配置标志不正确 错误及解决办法解决办法:如果是64位的office运行dcomcnfg打开组件服务如果是32位的office,则运行comexp.msc-32打开组件服务依次展开”组件服务”->“计算机”->“我的电脑”->“DCOM配置”找到”MicrosoftExcel应用程序”或”MicrosoftWord应用程序”,点击”安全”选项卡,依次把”启动和激活权限”,”访问权限”都选择为自定义,然后依次点击它们的编辑,把NetworkService和IIS_IUSRS添加进去,并加入所有的权限…

  • 操作系统第二章进程的描述与控制_进程同步和互斥的区别

    操作系统第二章进程的描述与控制_进程同步和互斥的区别什么是进程同步进程互斥的原则进程互斥的软件实现方法1、单标志法2、双标志先检查法3、双标志后检查法4、Peterson算法进程互斥的硬件实现方法1、中断屏蔽方法2、TestAndSetLock指令TSL和中断屏蔽的区别利用TSL完成进程间互斥-《现代操作系统》P713、XCHG指令信号量机制1、整型信号量2、记录型信号量(默认)记录型信号量定义P操作(wait操作)V操作(signal操作)信号量机制实现进程互斥信号量机制实现进程同步-前V后

发表回复

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

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