Android SDK 中为我们提供了一个现成的Service类来实现这个功能,它就是IntentService,它主要负责以下几个方面:
Creates a default worker thread that executes all intents delivered to onStartCommand()
separate from your application's main thread.
生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至 onStartCommand() 方法的Intetnt
Creates a work queue that passes one intent at a time to your onHandleIntent()
implementation, so you never have to worry about multi-threading.
生成一个工作队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就不必担心多线程的问题
Stops the service after all start requests have been handled, so you never have to call stopSelf()
.
在所有的请求(Intent)都被执行完以后会自动停止服务,所以,你不需要自己去调用stopSelf()方法来停止该服务
Provides default implementation of onBind()
that returns null.
提供了一个onBind()方法的默认实现,它返回null
Provides a default implementation of onStartCommand()
that sends the intent to the work queue and then to your onHandleIntent()
implementation
提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工作队列,然后从工作队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理
给出一个例子:
/ activity 的onCreate() @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); startSer1 = (Button) findViewById(R.id.startSer1); stopSer1 = (Button) findViewById(R.id.stopSer1); startSer2 = (Button) findViewById(R.id.startSer2); stopSer2 = (Button) findViewById(R.id.stopSer2); log = (TextView) findViewById(R.id.log); logView = (ScrollView) findViewById(R.id.logView); startSer1.setOnClickListener(btnListener); stopSer1.setOnClickListener(btnListener); startSer2.setOnClickListener(btnListener); stopSer2.setOnClickListener(btnListener); intent = new Intent(MyServiceActivity.this, IntentServiceDemo.class); // 打印出主线程的ID long id = Thread.currentThread().getId(); updateLog(TAG + " ----> onCreate() in thread id: " + id); }
// service 代码 package com.archer.rainbow; import java.text.SimpleDateFormat; import java.util.Date; import android.app.IntentService; import android.content.Intent; public class IntentServiceDemo extends IntentService { private static final String TAG = "IntentServiceDemo"; private static final SimpleDateFormat SDF_DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS"); public IntentServiceDemo() { super(TAG); MyServiceActivity.updateLog(TAG + " ----> constructor"); } @Override public void onCreate() { super.onCreate(); // 打印出该Service所在线程的ID long id = Thread.currentThread().getId(); MyServiceActivity.updateLog(TAG + " ----> onCreate() in thread id: " + id); } @Override public void onDestroy() { super.onDestroy(); MyServiceActivity.updateLog(TAG + " ----> onDestroy()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { MyServiceActivity.updateLog(TAG + " ----> onStartCommand()"); // 记录发送此请求的时间 intent.putExtra("time", System.currentTimeMillis()); return super.onStartCommand(intent, flags, startId); } @Override public void setIntentRedelivery(boolean enabled) { MyServiceActivity.updateLog(TAG + " ----> setIntentRedelivery()"); super.setIntentRedelivery(enabled); } @Override protected void onHandleIntent(Intent intent) { // 打印出处理intent所用的线程的ID long id = Thread.currentThread().getId(); MyServiceActivity.updateLog(TAG + " ----> onHandleIntent() in thread id: " + id); long time = intent.getLongExtra("time", 0); Date date = new Date(time); try { // 打印出每个请求对应的触发时间 MyServiceActivity.updateLog(TAG + " ----> onHandleIntent(): 下载文件中..." + SDF_DATE_FORMAT.format(date)); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }
从此图中可以看出,IntentServiceDemo的onCreate()所处的线程ID仍为1,说明它是在主线程中被执行的,且只被执行一次。然后,我每点击一次按钮,它都会触发一下onStartCommand()方法。仔细看第二次与第三次的onCommand()方法以及onHandleIntent()打印出来的语句,你会发现,第二、三两次点击按钮与第一次点击按钮的时间是没有超过3秒钟的,它们是连续被执行的,这说明了什么呢?说明,在第一个intent被处理时(即onHandleIntent()处于运行中),该Service仍然可以接受新的请求,但接受到新的请求后并没有立即执行,而是将它们放入了工作队列中,等待被执行。