IntentService用法解析

本文详细介绍了Android中的IntentService组件,包括其工作原理、如何创建及使用。通过示例代码展示了IntentService处理后台耗时任务的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

众所周知,service可以用来执行后台任务。但是我们不能把类似下载等这样的耗时任务直接放在service里面执行,否则会造成ANR。一般遇到这样的情况我们有两种处理方式:

1.自己创建并管理线程来执行这些耗时操作

2.通过IntentService实现。

这里通过模拟耗时任务的方式来简单介绍下IntentService的实现方式:

第一步:写一个IntentService的子类

IntentService子类必须重写onHandleIntent(Intent intent),该方法是在子线程执行的,可以用来处理耗时任务,这里的Intent对象是从Activity中传递进来的。至于为什么后面再具体分析。

public class CustomIntentSerivce extends IntentService{
    public String TAG = getClass().getSimpleName();
    public static String EXTRA = "extra";

    private int i=0;

    public CustomIntentSerivce() {
        super("customintentservice");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        //可以在这个方法中处理耗时任务
        if(intent!=null){
            i =intent.getIntExtra(CustomIntentSerivce.EXTRA,-1);
        }
        //这里打印当前的线程id
        Log.i(TAG, "i:  "+i+"   onHandleIntent Thread name: "+Thread.currentThread().getName()
                +"  id:"+Thread.currentThread().getId());

        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: ");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        //这里打印当前的线程id
        Log.i(TAG, "CustomIntentSerivce  Thread: "+Thread.currentThread().getId());
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return super.onBind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind: ");
        return super.onUnbind(intent);
    }

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

第二步:在Manifest.xml中注册Service

<service android:name=".CustomIntentSerivce"/>

第三步:在MainActivity中启动CustomIntentSerivce

public class MainActivity extends AppCompatActivity {

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

    private void initView() {
        findViewById(R.id.btn_start_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                testIntentService();
            }
        });
    }

    private void testIntentService() {
        Intent intent1 = new Intent(MainActivity.this,CustomIntentSerivce.class);
        intent1.putExtra(CustomIntentSerivce.EXTRA,1);
        startService(intent1);

        Intent intent2 = new Intent(MainActivity.this,CustomIntentSerivce.class);
        intent2.putExtra(CustomIntentSerivce.EXTRA,2);
        startService(intent2);

        Intent intent3 = new Intent(MainActivity.this,CustomIntentSerivce.class);
        intent3.putExtra(CustomIntentSerivce.EXTRA,3);
        startService(intent3);

    }
}

其中activity_main布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.android.lanjing.intentservice.MainActivity">

    <Button
        android:id="@+id/btn_start_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="启动IntentService"
        android:layout_centerInParent="true"/>
</RelativeLayout>

在MainActivity中通过startService(Intent intent)的方式启动service,虽然启动了3次但是Service的实例只会创建一个,即只执行一次Service的onCreate(),但是会执行3次onStartCommond()。

通过分析IntentService的源码可以发现在onCreate()中初始化了一个HandlerThread对象(线程):thread,同时调用thread.start()启动线程,在HandlerThread的run()内部有初始化Looper的操作。然后通过thread.getLooper()拿到这个线程的Looper,用这个Looper对象初始化ServiceHandler对象。源码如下:

@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 = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

这样在IntentService的内部就可以通过ServiceHandler发送消息了,该消息的处理操作最终是在子线程HandlerThread中完成的。

继续分析IntentService类,可以看到在IntentService的onStartCommand(Intent intent, int flags, int startId)方法中调用了onStart(intent, startId)。在onStart(intent, startId)中封装了一个Message,同时通过ServiceHandler将消息发送到消息队列中等待处理。源码如下:

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

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

这里可以看到从MainActivity中传递进来的Intent对象即是Message的obj属性的值,startId是Message的arg1属性值,该值在停止IntentService时会用到。

现在再来看下ServiceHandler这个类的源码:

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);
        }
    }

可以看到在ServiceHandler类的handleMessage(Message msg)方法中将message的obj强转为Intent对象(就是从MainActivity中传递过来的)。通过调用抽象方法onHandleIntent((Intent)msg.obj)来将具体的耗时操作暴露给开发人员去完成。

同时在onHandleIntent((Intent)msg.obj)后面调用了stopSelf(msg.arg1)方法,即通过startId停止IntentService,因此IntentService启动之后不需要开发人员手动去调用stopService(intent1),任务完成之后它自己会销毁。

下面是运行程序点击按钮后打印的日志:

23474-23474 I/CustomIntentSerivce: onCreate: 
23474-23474 I/CustomIntentSerivce: onStartCommand: 
23474-23474 I/CustomIntentSerivce: CustomIntentSerivce  Thread: 1
23474-23474 I/CustomIntentSerivce: onStartCommand: 
23474-23474 I/CustomIntentSerivce: CustomIntentSerivce  Thread: 1
23474-23474 I/CustomIntentSerivce: onStartCommand: 
23474-23474 I/CustomIntentSerivce: CustomIntentSerivce  Thread: 1
23474-24209 I/CustomIntentSerivce: i:  1   onHandleIntent Thread name: IntentService[customintentservice]  id:12824
23474-24209 I/CustomIntentSerivce: i:  2   onHandleIntent Thread name: IntentService[customintentservice]  id:12824
23474-24209 I/CustomIntentSerivce: i:  3   onHandleIntent Thread name: IntentService[customintentservice]  id:12824
23474-23474 I/CustomIntentSerivce: onDestroy: 

通过日志可以看出在onStartCommand(Intent intent, int flags, int startId)方法中打印的线程id是:1,在onHandleIntent(Intent intent)方法中打印的线程id是:12824,证实了onHandleIntent()方法是在子线程中执行的。

至此IntentService的介绍就差不多了,如有不对的地方请读者指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值