美文网首页
Service(五) - IntentService

Service(五) - IntentService

作者: 世道无情 | 来源:发表于2019-01-27 16:25 被阅读0次

    1. 概述


    对于开发中的一些耗时操作,比如上传多张图片、下载任务等,然后把 应用置于后台,自己干别的事情,此时Activity可能会被杀死,做法是可以直接交给Service去做,担心Service被杀死,可以设置前台Service;

    对于Service执行耗时操作,有2种处理方式:
    方式1:在 Service中开子线程;
    方式2:用 IntentService;

    2. IntentService


    IntentService 继承于 Service,用于处理 异步请求,用 startService开启服务,完成任务后会自己自动关闭服务,并且请求是在子线程中完成的;

    好处:
    1>:不用自己 new Thread() 开线程;
    2>:不用考虑什么时候关闭Service;

    3. IntentService使用


    效果图如下:

    图片.png

    每点击一次按钮,就会创建一个上传任务,然后交给后台Service处理,后台Service每处理完一个任务,就会用发送一个广播,通知该Activity进行更新UI,当所有任务完成,后台Service会自动退出,不会占用内存;

    sendBroadcast发送广播用法和EventBus用法类似:
    需要在该Activity中 注册、反注册广播,然后创建BroadcastReceive,在 onReceive()方法处理更新UI即可;

    代码如下:
    1>:activity_intentservice.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/id_ll_taskcontainer"
        >
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="添加任务"
            android:onClick="addTask"
            />
    </LinearLayout>
    
    2>:IntentServiceActivity:
    /**
     * ================================================
     * Email: 2185134304@qq.com
     * Created by Novate 2018/12/24 10:22
     * Version 1.0
     * Params:
     * Description:
     *
     *      备注:广播用法 和EventBus一样
     *
     *      注册、反注册相当于EventBus中的注册和反注册
     *      BroadcastReceiver中的 onReceive()方法相当于EventBus通知的 onEventMainThread() 方法
     * ================================================
    */
    
    public class IntentServiceActivity extends AppCompatActivity {
    
        private LinearLayout id_ll_taskcontainer;
    
    
        /**
         * 广播接收者:
         *      用于接收 UploadImgService 中 sendBroadcast发送的 UPLOAD_RESULT和IMG_PATH
         */
        private BroadcastReceiver uploadImgReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // 这里取出intent.getAction(),判断是否和UPLOAD_RESULT一样,如果一样
                if (intent.getAction()  == "UPLOAD_RESULT"){
                    // 就取出传递过来的 图片IMG_PATH路径
                    String path = intent.getStringExtra("IMG_PATH") ;
    
                    // 处理上传成功后的结果
                    handleResult(path) ;
                }
            }
        } ;
    
    
        /**
         * 处理上传成功后的结果
         */
        private void handleResult(String path) {
            // 根据标记取出给每个子view tv 的控件,设置值
            TextView tv = (TextView) id_ll_taskcontainer.findViewWithTag(path);
            tv.setText(path + "upload success ...");
        }
    
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_intentservice);
    
            id_ll_taskcontainer = (LinearLayout) findViewById(R.id.id_ll_taskcontainer);
    
            // 注册广播
            registerReceiver() ;
        }
    
        /**
         * 注册广播
         */
        private void registerReceiver() {
            IntentFilter intentFilter = new IntentFilter() ;
            intentFilter.addAction("UPLOAD_RESULT");
            registerReceiver(uploadImgReceiver , intentFilter) ;
        }
    
        /**
         * 注销广播
         */
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(uploadImgReceiver);
        }
    
    
        int i = 0;
        /**
         * 场景:
         *      1. 每点击一次按钮,就创建一个上传任务,交给 UploadImgService处理;
         *      2. 当Service的每个任务完成后,发送一个广播,然后在 此Activity注册、反注册广播,当接收到广播后就更新指定的UI;
         */
        public void addTask(View view) {
            // 模拟路径
            String path = "/sdcard/imgs/" + (++i) + ".png" ;
            // 开启一个UploadImgService 开始上传任务
            Intent intent = new Intent(this , UploadImgService.class) ;
            intent.setAction("UPLOAD_IMG");
            intent.putExtra("path" , path) ;
            IntentServiceActivity.this.startService(intent);
    
    
            // 动态的 把子view 添加 到 父view容器中
            TextView tv = new TextView(this) ;
            id_ll_taskcontainer.addView(tv);
            tv.setText(path + "is uploading ... ");
    
            // 给子view的tv设置一个标记,用path
            tv.setTag(path);
        }
    }
    
    3>:UploadImgService
    /**
     * ================================================
     * Email: 2185134304@qq.com
     * Created by Novate 2018/12/24 10:58
     * Version 1.0
     * Params:
     * Description:    用于处理耗时任务
     * ================================================
    */
    
    public class UploadImgService extends IntentService {
    
        /**
         * 需要一个无参构造方法
         */
        public UploadImgService(){
            super("UploadImgService");
        }
    
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    
    
        /**
         * 此方法是在主线程,由源码可知:
         *       @Override
         *       public void handleMessage(Message msg) {
         *           onHandleIntent((Intent)msg.obj);
         *           stopSelf(msg.arg1);
         *       }
         */
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            if (intent != null){
                // IntentServiceActivity 中传递过来的 action
                String action = intent.getAction();
                if ("UPLOAD_IMG".equals(action)){
                    // IntentServiceActivity 中传递过来的 path
                    String path = intent.getStringExtra("path");
    
                    // 获取到 IntentServiceActivity 中传递过来的action与path之后,开始上传任务
                    handleUploadImg(path) ;
                }
            }
        }
    
    
        /**
         * 开始上传任务
         */
        private void handleUploadImg(String path) {
            try {
                // 模拟3秒耗时上传任务
                Thread.sleep(3000);
    
                // 3秒后就表示上传成功,然后用广播通知IntentServiceActivity更新UI
                // 这里设置 UPLOAD_RESULT和IMG_PATH用于在IntentServiceActivity中做判断,然后取出值
                Intent intent = new Intent() ;
                intent.setAction("UPLOAD_RESULT");
                intent.putExtra("IMG_PATH" , path);
    
                // 这里的发送广播和 EventBus.getDefault().post(orderSuccess); 一样
                sendBroadcast(intent);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    4. IntentService源码分析


    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        private volatile ServiceHandler mServiceHandler;
        private String mName;
        private boolean mRedelivery;
    
        // ServiceHandler  继承 Handler
        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
            
            // 在handleMessage()中取出 msg消息,然后调用 onHandleIntent()方法,这个方法就是我们自己实现的
            @Override
            public void handleMessage(Message msg) {
                // 自己在代码中实现的方法 
                onHandleIntent((Intent)msg.obj);
                // 这里自动关闭 Service
                stopSelf(msg.arg1);
            }
        }
    
        public IntentService(String name) {
            super();
            mName = name;
        }
    
        public void setIntentRedelivery(boolean enabled) {
            mRedelivery = enabled;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            // 创建 HandlerThread 对象,这个是子线程,继承Thread
            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,其实就是 handler发送消息 msg, msg中包含intent
            mServiceHandler.sendMessage(msg);
        }
    
        @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            // 只要调用onStartCommand()方法,就会调用 onStart()方法,
            onStart(intent, startId);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
    
        @Override
        public void onDestroy() {
            mServiceLooper.quit();
        }
    
        @Override
        @Nullable
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        // 自己实现的 onHandleIntent()方法
        @WorkerThread
        protected abstract void onHandleIntent(@Nullable Intent intent);
    }
    

    1>:在 onCreate()方法中 创建 HandlerThread对象,继承Thread,是子线程,每次调用 onStartCommand()方法都会调用 onStart()方法;
    2>:在 onStart()方法中用 mServiceHandler(其实就是 Handler)调用mServiceHandler.sendMessage()发送消息,然后在 ServiceHandler 的 handleMessage()方法中调用 onHandleIntent() ,这个 onHandleIntent()就是我们自己重写的方法,把要处理的 耗时任务放到 这个方法就可以;
    3>:stopSelf(msg.arg1):执行完所有耗时任务后,回调这个方法,msg.arg1是一个int值,相当于请求的一个标识,每发送一个请求,就生成一个唯一标识,然后把请求放入队列,耗时任务全部执行完后,会销毁Service;
    4>:销毁Service会 回调onDestroy(),在 onDestroy()中调用 mServiceLooper.quit(),停止looper;

    相关文章

      网友评论

          本文标题:Service(五) - IntentService

          本文链接:https://www.haomeiwen.com/subject/gbabkqtx.html