IntentService的使用

为什么用IntentService

我们知道服务是在后台运行的,但是它本身存在两个问题:

  1. Service不会专门去启动一个新的进程,它与所在的应用属于同一个进程
  2. Service也不会专门去启动一个新的线程,它运行在主线程之中

    但是有的时候Service需要执行一些耗时操作,比如下载等,由于Service是在主线程中运行的,我们知道,如果主线程堵塞,会引发ANR,因此我们可以在Service中开启一个新的线程来运行,并且在运行结束后调用stopSelf或者stopService来停止该服务,这样可行,但是自己去管理Service的生命周期和子线程并不是一个好的选择,因此android提供了IntentService来处理这些工作。

IntentService简介

IntentService会采取队列的方式处理请求的Intent,每当客户端通过Intent请求IntentService时,IntentService便会将该Intent请求放在队列中,并开启一个新的worker线程来处理该Intent。对于异步的startService请求,IntentService会按照次序处理请求的Intent,该线程保证同一时刻只处理一个Intent,由于是在新的worker线程中处理,因此不会发生阻塞主线程的情况。

IntentService的特征

  1. IntentService会开启新的worker线程来处理所有的Intent请求
  2. IntentService会开启新的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无需处理多线程问题
  3. 在所有请求处理完成后,IntentService会自动停止,开发者无需调用stopSelf()方法来停止
  4. IntentService为onBind()方法提供了默认的实现,默认返回null
  5. IntentService为onStartCommand()方法提供了默认的实现,会将请求的Intent加入到请求队列中

开发实例,模拟下载

这里写图片描述

一些常量的设置

    //开启IntentService的action值
    public static final String ACTION_UPLOAD_IMG="com.xu.intentservice.action.UPLOAD_IMG";
    //传递path的KEY值
    public static final String EXTRA_IMG_PATH="com.xu.intentsrevice.extra.IMG_PATH";
    //广播Intent的action
    public static final String UPLOAD_RESULT="com.xu.intentservice.UPLOAD_RESULT";

主界面有一个Add Task按钮,每点击一下就会开始一个下载任务,并且将需要下载的文件地址传进去,并且在主界面添加一个TextView,为它设置唯一标识为path

mAddTaskButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //构建下载的虚拟路径
                String path="/sdcard/imgs/"+(++i)+".jpg";
                //构建intent用于开启Service
                Intent intent=new Intent(MainActivity.this,UpLoadingService.class);
                //设置action
                intent.setAction(ACTION_UPLOAD_IMG);
                //将地址传过去
                intent.putExtra(EXTRA_IMG_PATH, path);
                //开启IntentService
                startService(intent);

                //新建一个TextView
                TextView tv=new TextView(MainActivity.this);
                mContainerLinear.addView(tv);
                tv.setText(path+"---is loading......");
                tv.setTextSize(20);
                //将path设置为TextView的TAG,唯一标识
                tv.setTag(path);
            }
        });

在UpLoadingService类中重写了onHandleIntent方法,开启Service,并且接收到传进来的Intent附带的EXTRA即path,然后自定义方法handleUpLoading方法通过传递进来的path属性来处理下载,当然这里只是让线程休眠了3秒来模拟下载,下载完成后,发送一条广播,并且将path值传递进去。

@Override
    protected void onHandleIntent(Intent intent) {
        if(intent!=null){
            String action=intent.getAction();
            //判断intent的action
            if(MainActivity.ACTION_UPLOAD_IMG.equals(action)){
                //获取到intent携带的path
                String path=intent.getStringExtra(MainActivity.EXTRA_IMG_PATH);
                //处理下载
                handleUploadImg(path);
                Log.i(TAG,"---------"+Thread.currentThread().getId());
            }
        }
    }

处理下载,发送广播

private void handleUploadImg(String path){
        try {
            //线程休眠3秒模拟下载时间
            Thread.sleep(3000);
            //设置将要发送的广播的值的intent
            Intent intent=new Intent(MainActivity.UPLOAD_RESULT);
            //将路径带进去
            intent.putExtra(MainActivity.EXTRA_IMG_PATH, path);
            //发送广播
            sendBroadcast(intent);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

在MainActivity中建立广播接收器,接收到广播意味着下载完成,并且通过传递进来的path值通过findViewWithTag找到刚才的TextView,设置为下载完成。

private BroadcastReceiver uploadImgReceive=new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            //接受这个广播
            String action=intent.getAction();
            if(action.equals(UPLOAD_RESULT));
            //得到path
            String path=intent.getStringExtra(EXTRA_IMG_PATH);
            //处理下载好以后的处理
            handleResult(path);

        }
    };
    //处理下载结果
    public void handleResult(String path){
        //通过刚才设置的TAG值得到TextView
        mShowTextView=(TextView) mContainerLinear.findViewWithTag(path);
        mShowTextView.setText(path+"upload succeed----");
    }

注册广播接收器

    public void registerReceiver(){
        //设置要接受的广播
        IntentFilter filter=new IntentFilter();
        filter.addAction(UPLOAD_RESULT);
        //注册
        registerReceiver(uploadImgReceive,filter);
    }

我在IntentService的onHandleIntent方法中打印出了当前线程的Id,可以看到不是使用的主线程,并且按照顺序处理Intent请求,且使用的同一个worker线程。

这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值