一.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. * * <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; } @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; }
过程分析:
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的地址:不知道为什么上传不了!