IntentService

一、IntentService简介

IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:

Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;

Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;

二、IntentService特征

会创建独立的worker线程来处理所有的Intent请求;

会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;

所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;

为Service的onBind()提供默认实现,返回null;

为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;

三、使用步骤(详情参考Service项目)

继承IntentService类,并重写onHandleIntent()方法即可;

MainActivity.java文件

[java]view plaincopy

publicclassMainActivityextendsActivity {

@Override

protectedvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

publicvoidstartService(View source) {

// 创建所需要启动的Service的Intent

Intent intent =newIntent(this, MyService.class);

startService(intent);

}

publicvoidstartIntentService(View source) {

// 创建需要启动的IntentService的Intent

Intent intent =newIntent(this, MyIntentService.class);

startService(intent);

}

}

MyIntentService.java文件

[java]view plaincopy

publicclassMyIntentServiceextendsIntentService {

publicMyIntentService() {

super("MyIntentService");

}

@Override

protectedvoidonHandleIntent(Intent intent) {

// IntentService会使用单独的线程来执行该方法的代码

// 该方法内执行耗时任务,比如下载文件,此处只是让线程等待20秒

longendTime = System.currentTimeMillis() +20*1000;

System.out.println("onStart");

while(System.currentTimeMillis() < endTime) {

synchronized(this) {

try{

wait(endTime - System.currentTimeMillis());

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

System.out.println("----耗时任务执行完成---");

}

}

MyService.java文件

[java]view plaincopy

publicclassMyServiceextendsService {

@Override

publicIBinder onBind(Intent arg0) {

returnnull;

}

@Override

publicintonStartCommand(Intent intent,intflags,intstartId) {

// 该方法内执行耗时任务可能导致ANR(Application Not Responding)异常

longendTime = System.currentTimeMillis() +20*1000;

System.out.println("onStart");

while(System.currentTimeMillis() < endTime) {

synchronized(this) {

try{

wait(endTime - System.currentTimeMillis());

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}

System.out.println("----耗时任务执行完成---");

returnSTART_STICKY;

}

}

运行上述代码,启动MyIntentService的会使用单独的worker线程,因此不会阻塞前台的UI线程;而MyService会。



在Android开发中,我们或许会碰到这么一种业务需求,一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功。那么,利用几个子线程顺序执行是可以达到这个目的的,但是每个线程必须去手动控制,而且得在一个子线程执行完后,再开启另一个子线程。或者,全部放到一个线程中让其顺序执行。这样都可以做到,但是,如果这是一个后台任务,就得放到Service里面,由于Service和Activity是同级的,所以,要执行耗时任务,就得在Service里面开子线程来执行。那么,有没有一种简单的方法来处理这个过程呢,答案就是IntentService。

什么是IntentService,首先看看官方的解释:

IntentService is a base class forServices that handle asynchronous requests (expressed asIntents) on demand. Clients send requests throughstartService(Intent)calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work

简单说,IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

还有一个说明是:

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

大致意思是:所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。

那么,用IntentService有什么好处呢?首先,我们省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service,第三,it's so easy to use!

ok,接下来让我们来看看如何使用,我写了一个Demo来模拟两个耗时操作,Operation1与Operation2,先执行1,2必须等1执行完才能执行:

新建工程,新建一个继承IntentService的类,我这里是IntentServiceDemo.java

[java]view plaincopy

publicclassIntentServiceDemoextendsIntentService {

publicIntentServiceDemo() {

//必须实现父类的构造方法

super("IntentServiceDemo");

}

@Override

publicIBinder onBind(Intent intent) {

System.out.println("onBind");

returnsuper.onBind(intent);

}

@Override

publicvoidonCreate() {

System.out.println("onCreate");

super.onCreate();

}

@Override

publicvoidonStart(Intent intent,intstartId) {

System.out.println("onStart");

super.onStart(intent, startId);

}

@Override

publicintonStartCommand(Intent intent,intflags,intstartId) {

System.out.println("onStartCommand");

returnsuper.onStartCommand(intent, flags, startId);

}

@Override

publicvoidsetIntentRedelivery(booleanenabled) {

super.setIntentRedelivery(enabled);

System.out.println("setIntentRedelivery");

}

@Override

protectedvoidonHandleIntent(Intent intent) {

//Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务

String action = intent.getExtras().getString("param");

if(action.equals("oper1")) {

System.out.println("Operation1");

}elseif(action.equals("oper2")) {

System.out.println("Operation2");

}

try{

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}

@Override

publicvoidonDestroy() {

System.out.println("onDestroy");

super.onDestroy();

}

}

我把生命周期方法全打印出来了,待会我们来看看它执行的过程是怎样的。接下来是Activity,在Activity中来启动IntentService:

[java]view plaincopy

publicclassTestActivityextendsActivity {

/** Called when the activity is first created. */

@Override

publicvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

//可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个

//Operation 1

Intent startServiceIntent =newIntent("com.test.intentservice");

Bundle bundle =newBundle();

bundle.putString("param","oper1");

startServiceIntent.putExtras(bundle);

startService(startServiceIntent);

//Operation 2

Intent startServiceIntent2 =newIntent("com.test.intentservice");

Bundle bundle2 =newBundle();

bundle2.putString("param","oper2");

startServiceIntent2.putExtras(bundle2);

startService(startServiceIntent2);

}

}

最后,别忘了配置Service,因为它继承于Service,所以,它还是一个Service,一定要配置,否则是不起作用的,开始我就是忘了,结果半天没反应。

[html]view plaincopy

ok,最后来看看执行结果:

IntentService_第1张图片

从结果可以看到,onCreate方法只执行了一次,而onStartCommand和onStart方法执行了两次,开启了两个Work Thread,这就证实了之前所说的,启动多次,但IntentService的实例只有一个,这跟传统的Service是一样的。Operation1也是先于Operation2打印,并且我让两个操作间停顿了2s,最后是onDestroy销毁了IntentService。


一 概述

大家都清楚,在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activity就很可能会被杀死,所以可以考虑将上传操作交给Service去做,如果担心Service被杀,还能通过设置startForeground(int, Notification)方法提升其优先级。

那么,在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在Android给我们提供了一个类,叫做IntentService,我们看下注释。

IntentService is a base class for {@link Service}s that handle asynchronous

requests (expressed as {@link Intent}s) on demand. Clients send requests

through {@link android.content.Context#startService(Intent)} calls; the

service is started as needed, handles each Intent in turn using a worker

thread, and stops itself when it runs out of work.

意思说IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。

这么说,我们使用了IntentService最起码有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。

好了,那么接下来我们就来看一个完整的例子。

二 IntentService的使用

我们就来演示一个多个图片上传的案例,当然我们会模拟上传的耗时,毕竟我们的重心在IntentService的使用和源码解析上。

首先看下效果图

效果图

IntentService_第2张图片

每当我们点击一次按钮,会将一个任务交给后台的Service去处理,后台的Service每处理完成一个请求就会反馈给Activity,然后Activity去更新UI。当所有的任务完成的时候,后台的Service会退出,不会占据任何内存。

Service

packagecom.zhy.blogcodes.intentservice;importandroid.app.IntentService;importandroid.content.Context;importandroid.content.Intent;importandroid.util.Log;publicclassUploadImgServiceextendsIntentService{privatestaticfinalString ACTION_UPLOAD_IMG ="com.zhy.blogcodes.intentservice.action.UPLOAD_IMAGE";publicstaticfinalString EXTRA_IMG_PATH ="com.zhy.blogcodes.intentservice.extra.IMG_PATH";publicstaticvoidstartUploadImg(Context context, String path)    {        Intent intent =newIntent(context, UploadImgService.class);        intent.setAction(ACTION_UPLOAD_IMG);        intent.putExtra(EXTRA_IMG_PATH, path);        context.startService(intent);    }publicUploadImgService()    {super("UploadImgService");    }@OverrideprotectedvoidonHandleIntent(Intent intent)    {if(intent !=null)        {finalString action = intent.getAction();if(ACTION_UPLOAD_IMG.equals(action))            {finalString path = intent.getStringExtra(EXTRA_IMG_PATH);                handleUploadImg(path);            }        }    }privatevoidhandleUploadImg(String path)    {try{//模拟上传耗时Thread.sleep(3000);            Intent intent =newIntent(IntentServiceActivity.UPLOAD_RESULT);            intent.putExtra(EXTRA_IMG_PATH, path);            sendBroadcast(intent);        }catch(InterruptedException e)        {            e.printStackTrace();        }    }@OverridepublicvoidonCreate()    {super.onCreate();        Log.e("TAG","onCreate");    }@OverridepublicvoidonDestroy()    {super.onDestroy();        Log.e("TAG","onDestroy");    }

代码很短,主要就是继承IntentService,然后复写onHandleIntent方法,根据传入的intent来选择具体的操作。startUploadImg是我写的一个辅助方法,省的每次都去构建Intent,startService了。

Activity

packagecom.zhy.blogcodes.intentservice;importandroid.content.BroadcastReceiver;importandroid.content.Context;importandroid.content.Intent;importandroid.content.IntentFilter;importandroid.os.Bundle;importandroid.support.v7.app.AppCompatActivity;importandroid.view.Menu;importandroid.view.MenuItem;importandroid.view.View;importandroid.widget.LinearLayout;importandroid.widget.TextView;importcom.zhy.blogcodes.R;publicclassIntentServiceActivityextendsAppCompatActivity{publicstaticfinalString UPLOAD_RESULT ="com.zhy.blogcodes.intentservice.UPLOAD_RESULT";privateLinearLayout mLyTaskContainer;privateBroadcastReceiver uploadImgReceiver =newBroadcastReceiver()    {@OverridepublicvoidonReceive(Context context, Intent intent)        {if(intent.getAction() == UPLOAD_RESULT)            {                String path = intent.getStringExtra(UploadImgService.EXTRA_IMG_PATH);                handleResult(path);            }        }    };privatevoidhandleResult(String path)    {        TextView tv = (TextView) mLyTaskContainer.findViewWithTag(path);        tv.setText(path +" upload success ~~~ ");    }@OverrideprotectedvoidonCreate(Bundle savedInstanceState)    {super.onCreate(savedInstanceState);        setContentView(R.layout.activity_intent_service);        mLyTaskContainer = (LinearLayout) findViewById(R.id.id_ll_taskcontainer);        registerReceiver();    }privatevoidregisterReceiver()    {        IntentFilter filter =newIntentFilter();        filter.addAction(UPLOAD_RESULT);        registerReceiver(uploadImgReceiver, filter);    }inti =0;publicvoidaddTask(View view)    {//模拟路径String path ="/sdcard/imgs/"+ (++i) +".png";        UploadImgService.startUploadImg(this, path);        TextView tv =newTextView(this);        mLyTaskContainer.addView(tv);        tv.setText(path +" is uploading ...");        tv.setTag(path);    }@OverrideprotectedvoidonDestroy()    {super.onDestroy();        unregisterReceiver(uploadImgReceiver);    }}

Activity中,每当我点击一次按钮调用addTask,就回模拟创建一个任务,然后交给IntentService去处理。

注意,当Service的每个任务完成的时候,会发送一个广播,我们在Activity的onCreate和onDestroy里面分别注册和解注册了广播;当收到广播则更新指定的UI。


参考:http://blog.csdn.net/p106786860/article/details/17885115

http://blog.csdn.net/ryantang03/article/details/8146154

http://blog.csdn.net/lmj623565791/article/details/47143563

你可能感兴趣的:(IntentService)