zoukankan      html  css  js  c++  java
  • Android Intent Service

    Android Intent Service

    学习自

    Overview

    IntentService 是Service的子类,他被用来根据需求处理异步(IntentService中存在一个工作线程)请求(表现为Intent,从类的名字也可以看出来)。 而且这个Service非常省心,当工作完成后会自动停止,不需要我们手动停止。

    使用IntentService

    下面是一个简单的通过IntentService来更新进度条的示例,示例流程如下:

    1. Activity中祖册临时的广播接受者,来接收消息,然后更新UI
    2. 点击Button开启IntentService,然后开始增加进度
    3. 当增加了进度以后,通过发送广播,来通知UI改变

    6472982C-68A1-479B-AFBE-4A40564377ED

    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 = 0
    
        private lateinit var mLocalBroadcastManager: LocalBroadcastManager
    
        private var isRunning = true
    
        override 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 = 0
    
            while (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: LocalBroadcastManager
    
        override 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: LocalBroadcastManager
    
        lateinit var mService: TestIntentService.MyBinder
    
        private 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 中发送数据。

  • 相关阅读:
    Spring源码学习之容器的基本实现(一)
    面向对象设计原则
    简单易懂带你了解红黑树
    简单易懂带你了解二叉树
    单例模式
    原形模式
    数组与链表
    记一次解决postgresql数据库内存泄露的问题
    记一次排查CPU高的问题
    react ts 设置paths 和 声明非@types的模块
  • 原文地址:https://www.cnblogs.com/slyfox/p/9689627.html
Copyright © 2011-2022 走看看