一.IntentService的使用场景
在 Android
开发中,我们或许会碰到这么一种业务需求,一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功。那么,利用几个子线程顺序执行是可以达到这个目的的,但是每个线程必须去手动控制,而且得在一个子线程执行完后,再开启另一个子线程。或者,全部放到一个线程中让其顺序执行。这样都可以做到,但是,如果这是一个后台任务,就得放到Service里面,由于Service和Activity是同级的,所以,要执行耗时任务,就得在Service里面开子线程来执行。那么,有没有一种简单的方法来处理这个过程呢,答案就是IntentService。
二:IntentService的优点
Android中Services之异步IntentService
IntentService:异步处理服务,新开一个线程:handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务。
这么说,我们使用了IntentService最起码有两个好处,
一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了
。
三 IntentService简单demo
public class UploadImgService extends IntentService
{
String TAG="UploadImgService";
private static final String ACTION_UPLOAD_IMG = "com.poeng.blogcodes.intentservice.action.UPLOAD_IMAGE";
public static final String EXTRA_IMG_PATH = "com.peng.blogcodes.intentservice.extra.IMG_PATH";
public static void startUploadImg(Context context, String path)
{
Intent intent = new Intent(context, UploadImgService.class);
intent.setAction(ACTION_UPLOAD_IMG);
intent.putExtra(EXTRA_IMG_PATH, path);
context.startService(intent);
}
public UploadImgService()
{
super("UploadImgService");
}
/**
* 必须重写这个方法
* @param intent
*/
@Override
protected void onHandleIntent(Intent intent)
{
if (intent != null)
{
final String action = intent.getAction();
if (ACTION_UPLOAD_IMG.equals(action))
{
final String path = intent.getStringExtra(EXTRA_IMG_PATH);
handleUploadImg(path);
}
}
}
private void handleUploadImg(String path)
{
try
{
//模拟上传耗时
Thread.sleep(3500);
Intent intent = new Intent(MainActivity.UPLOAD_RESULT);
intent.putExtra(EXTRA_IMG_PATH, path);
sendBroadcast(intent);
Log.e(TAG, "handleUploadImg="+path);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "onStart");
super.onStart(intent, startId);
}
/**
* 每次启动Service都会调用多次
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate()
{
super.onCreate();
Log.e(TAG, "onCreate");
}
@Override
public void onDestroy()
{
super.onDestroy();
Log.e(TAG,"onDestroy");
}
public class MainActivity extends Activity {
public static final String UPLOAD_RESULT = "com.peng.blogcodes.intentservice.UPLOAD_RESULT";
private LinearLayout mLyTaskContainer;
private BroadcastReceiver uploadImgReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction() == UPLOAD_RESULT)
{
String path = intent.getStringExtra(UploadImgService.EXTRA_IMG_PATH);
handleResult(path);
}
}
};
/**
* 更具广播的回调结果更新UI
* @param path
*/
private void handleResult(String path)
{
TextView tv = (TextView) mLyTaskContainer.findViewWithTag(path);
tv.setText(path + " upload success ~~~ ");
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLyTaskContainer = (LinearLayout) findViewById(R.id.id_ll_taskcontainer);
registerReceiver();
}
/**
* 注册广播
*/
private void registerReceiver()
{
IntentFilter filter = new IntentFilter();
filter.addAction(UPLOAD_RESULT);
registerReceiver(uploadImgReceiver, filter);
}
int i = 0;
/**
* 点击事件执行方法
* @param view
*/
public void addTask(View view)
{
//模拟路径
String path = "/sdcard/imgs/" + (++i) + ".png";
UploadImgService.startUploadImg(this, path);
//动态添加控件,并且可以给控件设置TAG
TextView tv = new TextView(this);
mLyTaskContainer.addView(tv);
tv.setText(path + " is uploading ...");
tv.setTag(path);
}
@Override
protected void onDestroy()
{
super.onDestroy();
unregisterReceiver(uploadImgReceiver);
}
结果:
05-16 14:38:26.543 27674-27674/myintentservice.peng.cx.com.myintentservicedemo E/UploadImgService: onCreate
05-16 14:38:26.543 27674-27674/myintentservice.peng.cx.com.myintentservicedemo E/UploadImgService: onStartCommand
05-16 14:38:26.543 27674-27674/myintentservice.peng.cx.com.myintentservicedemo E/UploadImgService: onStart
05-16 14:38:30.036 27674-22347/myintentservice.peng.cx.com.myintentservicedemo E/UploadImgService: handleUploadImg=/sdcard/imgs/1.png
05-16 14:38:30.046 27674-27674/myintentservice.peng.cx.com.myintentservicedemo E/UploadImgService: onDestroy
以上总结;
通过多次启动Service,调用onStartCommand,onStartCommand调用了onHandleIntent,从而开始执行任务!
执行一个任务之后Service就会暂停。
如果开始了多个任务,通过多次启动service,会只有一个实例,有多个消息
消息队列里面的消息全部执行了,Service就会停止!
四.IntentService源码解析
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* 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.
*
* 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;
}
@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);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
需要先读懂
HandlerThread,连接地址: http://blog.csdn.net/whb20081815/article/details/67639060
过程分析:
1.
onCreate里面初始化了一个HandlerThread,它里面是开了线程和有自己的消息队列
2.
每次调用onStartCommand的时候,通过mServiceHandler发送一个消息
3.
handleMessage中回调onHandleIntent(intent)
4.
onHandleIntent执行完成之后就结束Service自己
总结:
IntentService有以下特点:
(1) 它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。
(2) 创建了一个工作队列,来逐个发送intent给onHandleIntent()。
(3) 不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。
(4) 默认实现的onBind()返回null
(5) 默认实现的onStartCommand()的目的是将intent插入到工作队列中
继承IntentService的类至少要实现两个函数:构造函数和onHandleIntent()函数。要覆盖IntentService的其它函数时,注意要通过super调用父类的对应的函数。
Demo的地址:不知道为什么上传不了!