Android Intent Service

枕上诗书闲处好,门前风景雨来佳。这篇文章主要讲述Android Intent Service相关的知识,希望能为你提供帮助。
android Intent Service 学习自

  • Android 官方文档
  • https://blog.csdn.net/iromkoear/article/details/63252665
Overview
【Android Intent Service】IntentService 是Service的子类,他被用来根据需求处理异步(IntentService中存在一个工作线程)请求(表现为Intent,从类的名字也可以看出来)。 而且这个Service非常省心,当工作完成后会自动停止,不需要我们手动停止。
使用IntentService
下面是一个简单的通过IntentService来更新进度条的示例,示例流程如下:
  1. Activity中祖册临时的广播接受者,来接收消息,然后更新UI
  2. 点击Button开启IntentService,然后开始增加进度
  3. 当增加了进度以后,通过发送广播,来通知UI改变
Android Intent Service

文章图片

IntentService
class TestIntentService(name: String?) : IntentService(name) { /** * 注意必须要有一个无参数的构造函数 * 当前环境使用的API是API26 * IntentService并没有无参数的构造函数 * 所以我们这里需要自己创建一个 * 否则会报错 * * name 参数 代表的工作线程的命名 * */ constructor() : this(" TestIntentService" ) {}companion object { val ACTION_UPDATE_PROGRESS = " com.shycoder.cn.studyintentservice.UPDATE_PROGRESS" }private var progress = 0private lateinit var mLocalBroadcastManager: LocalBroadcastManagerprivate var isRunning = trueoverride fun onCreate() { super.onCreate() this.mLocalBroadcastManager = LocalBroadcastManager.getInstance(this) }override fun onHandleIntent(intent: Intent?) {Log.e(" TAG" , " onHandleIntent" )if (intent == null || intent.action != ACTION_UPDATE_PROGRESS) { return }this.isRunning = true this.progress = 0while (isRunning) { SystemClock.sleep(500) progress += 10 if (progress > = 100) { this.isRunning = false } this.sendBroadcast(if (isRunning) " running" else " finish" , progress) } }/** * send broadcast to activity for notifying change of status and progress * */ private fun sendBroadcast(status: String, progress: Int) { val intent = Intent() intent.action = MainActivity.ACTION_STATUS_CHANGED intent.putExtra(" status" , status) intent.putExtra(" progress" , progress) this.mLocalBroadcastManager.sendBroadcast(intent) }}

Activity的代码
class MainActivity : AppCompatActivity() {val mReceiver = TestBroadcastReceiver() lateinit var mLocalBroadcastManager: LocalBroadcastManageroverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)//register broadcast val intentFilter = IntentFilter(ACTION_STATUS_CHANGED) this.mLocalBroadcastManager = LocalBroadcastManager.getInstance(this) mLocalBroadcastManager.registerReceiver(mReceiver, intentFilter) }/** * start intent service * */ fun startIntentService(view: View) { val intent = Intent(this, TestIntentService::class.java) intent.action = TestIntentService.ACTION_UPDATE_PROGRESS this.startService(intent) }override fun onDestroy() { super.onDestroy() this.unregisterReceiver(this.mReceiver)}inner class TestBroadcastReceiver : BroadcastReceiver() {override fun onReceive(context: Context?, intent: Intent?) { if (intent == null) { return } val status = intent.getStringExtra(" status" ) val progress = intent.getIntExtra(" progress" , 0) tvStatus.text = status progress_barTest.progress = progress} }companion object { val ACTION_STATUS_CHANGED = " cn.shycoder.studyintentservice.STATUS_CHANGED" } }

多次开启IntentService
当我们试着连续点击多次Button(比如说三次), 稍等片刻就会发现进度条满了以后,又重新开始了直到三次位置。打印出来的Log如下:
E/TAG: onHandleIntent E/TAG: onHandleIntent E/TAG: onHandleIntent

通过Log和UI的变化,我们可以发现,如果多次开启Service的话,那么 onHandleIntent 方法就会执行多次,这一点与 Service 大相庭径需要我们格外的关注,至于为什么是这种情况,在接下来的源码解析中会提到。
不要使用Bind的方式开启服务
在我们使用 Service 的时候,为了能和Service进行交互,我们会通过Bind的方式开启服务获取与Service进行通信的Binder,但是Bind开启服务的方式并不适用于 IntentService 下面我们来验证一下。
class TestIntentService(name: String?) : IntentService(name) { /** * 注意必须要有一个无参数的构造函数 * 当前环境使用的API是API26 * IntentService并没有无参数的构造函数 * 所以我们这里需要自己创建一个 * 否则会报错 * * name 参数 代表的工作线程的命名 * */ constructor() : this(" TestIntentService" ) {}private val mBinder = MyBinder()override fun onBind(intent: Intent?): IBinder { Log.e(" TAG" , " onBind" ) return this.mBinder }inner class MyBinder : Binder() { } //... }

绑定服务
class MainActivity : AppCompatActivity() { //.... lateinit var mLocalBroadcastManager: LocalBroadcastManagerlateinit var mService: TestIntentService.MyBinderprivate val mConn = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { mService = service as TestIntentService.MyBinder }override fun onServiceDisconnected(name: ComponentName?) { }}/** * bind intent service * */ fun bindService(view: View) { val intent = Intent(this, TestIntentService::class.java) intent.action = TestIntentService.ACTION_UPDATE_PROGRESS this.bindService(intent, this.mConn, Context.BIND_AUTO_CREATE) } //... }

当我们BindService后,查看Log
E/TAG: onBind

我们发现 onHandleIntent 方法的Log并没有打印出来,这时候 IntentService 就是一个普通的Service了,而不具备IntentService的特性。由此我们可以得出结论——不用使用Bind的方式开启IntentService。
IntentService源码解析
public abstract class IntentService extends Service { private volatile Looper mServiceLooper; //looper private volatile ServiceHandler mServiceHandler; //handler private String mName; //线程的名字 private boolean mRedelivery; /** 这个Handler是子线程的Handler,并不是与UI通信的Handler */ private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } /** 调用 onHandleIntent */ @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); //当所有的消息都处理完了就结束服务 stopSelf(msg.arg1); } }public IntentService(String name) { super(); mName = name; }public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; }@Override public void onCreate() {super.onCreate(); //实例化HandlerThread //HandlerThread继承自Thread HandlerThread thread = new HandlerThread(" IntentService[" + mName + " ]" ); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); }/** 众所周知,如果多次开启Service的话,那么 onStart方法就会执行多次 IntentService在onStart找那个不断地向Handler发送消息 */ @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }@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(); }/** onBind 方法被重写,返回null */ @Override @Nullable public IBinder onBind(Intent intent) { return null; }@WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent); }

上面的代码很简单,仅仅是对Service进行了一层封装,大致流程如下:
  1. 当创建service的时候,进行IntentService的初始化操作(onCreate),实例化 HandlerThread
  2. onCreate方法执行以后,紧接着就会调用 onStart 方法,这时候就像向Handler发送消息
  3. handler 会进行排队执行
  4. 当所有的消息都处理完成了以后,会将服务结束
为什么不能用Bind的方式开启IntentService通过查看源码,我想大家已经找到答案了。因为Start方式和Bind的方式开启Service的时候执行的生命周期的方法是不同的,通过Bind的方法开启Service,并不会执行 onStart 生命周期方法。 所以虽然 Bind的方式开启Service会执行onCreate方法来实例化 HandlerThread 但是因为 onStart 方法才向Handler 中发送数据。

    推荐阅读