zoukankan      html  css  js  c++  java
  • Android IntentService完全解析 当Service遇到Handler

    转载请标明出处: 
    http://blog.csdn.net/lmj623565791/article/details/47143563; 
    本文出自:【张鸿洋的博客】

    一 概述

    大家都清楚,在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activity就很可能会被杀死,所以可以考虑将上传操作交给Service去做,如果担心Service被杀,还能通过设置startForeground(int, Notification)方法提升其优先级。

    那么,在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在Android给我们提供了一个类,叫做IntentService,我们看下注释。

    IntentService is a base class for {@link Service}s that handle asynchronous 
    requests (expressed as {@link Intent}s) on demand. Clients send requests 
    through {@link android.content.Context#startService(Intent)} calls; the 
    service is started as needed, handles each Intent in turn using a worker 
    thread, and stops itself when it runs out of work.

    意思说IntentService是一个基于Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。

    这么说,我们使用了IntentService最起码有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。

    好了,那么接下来我们就来看一个完整的例子。

    二 IntentService的使用

    我们就来演示一个多个图片上传的案例,当然我们会模拟上传的耗时,毕竟我们的重心在IntentService的使用和源码解析上。

    首先看下效果图

    效果图

    每当我们点击一次按钮,会将一个任务交给后台的Service去处理,后台的Service每处理完成一个请求就会反馈给Activity,然后Activity去更新UI。当所有的任务完成的时候,后台的Service会退出,不会占据任何内存。

    Service

    package com.zhy.blogcodes.intentservice;
    
    import android.app.IntentService;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    public class UploadImgService extends IntentService
    {
        private static final String ACTION_UPLOAD_IMG = "com.zhy.blogcodes.intentservice.action.UPLOAD_IMAGE";
        public static final String EXTRA_IMG_PATH = "com.zhy.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");
        }
    
        @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(3000);
    
                Intent intent = new Intent(IntentServiceActivity.UPLOAD_RESULT);
                intent.putExtra(EXTRA_IMG_PATH, path);
                sendBroadcast(intent);
    
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
    
    
        }
    
        @Override
        public void onCreate()
        {
            super.onCreate();
            Log.e("TAG","onCreate");
        }
    
        @Override
        public void onDestroy()
        {
            super.onDestroy();
            Log.e("TAG","onDestroy");
        }
    }
    

    代码很短,主要就是继承IntentService,然后复写onHandleIntent方法,根据传入的intent来选择具体的操作。startUploadImg是我写的一个辅助方法,省的每次都去构建Intent,startService了。

    Activity

    package com.zhy.blogcodes.intentservice;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import com.zhy.blogcodes.R;
    
    public class IntentServiceActivity extends AppCompatActivity
    {
    
        public static final String UPLOAD_RESULT = "com.zhy.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);
    
                }
    
            }
        };
    
        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_intent_service);
    
            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;
    
        public void addTask(View view)
        {
            //模拟路径
            String path = "/sdcard/imgs/" + (++i) + ".png";
            UploadImgService.startUploadImg(this, path);
    
            TextView tv = new TextView(this);
            mLyTaskContainer.addView(tv);
            tv.setText(path + " is uploading ...");
            tv.setTag(path);
        }
    
    
        @Override
        protected void onDestroy()
        {
            super.onDestroy();
            unregisterReceiver(uploadImgReceiver);
        }
    }
    
    

    Activity中,每当我点击一次按钮调用addTask,就回模拟创建一个任务,然后交给IntentService去处理。

    注意,当Service的每个任务完成的时候,会发送一个广播,我们在Activity的onCreate和onDestroy里面分别注册和解注册了广播;当收到广播则更新指定的UI。

    布局文件

    <LinearLayout android:id="@+id/id_ll_taskcontainer"
                  xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
                 >
    
    
        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
                android:onClick="addTask" android:text="add Task"/>
    </LinearLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ok,这样我们就完成了我们的效果图的需求;通过上例,大家可以看到我们可以使用IntentService非常方便的处理后台任务,屏蔽了诸多细节;而Service与Activity通信呢,我们选择了广播的方式(当然这里也可以使用LocalBroadcastManager)。

    学会了使用之后,我们再一鼓作气的看看其内部的实现。

    三 IntentService源码解析

    直接看IntentService源码

    /*
     * Copyright (C) 2008 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package android.app;
    
    import android.content.Intent;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.os.Looper;
    import android.os.Message;
    
    
    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);
            }
        }
    
    
        public IntentService(String name) {
            super();
            mName = name;
        }
    
    
        public void setIntentRedelivery(boolean enabled) {
            mRedelivery = enabled;
        }
    
        @Override
        public void onCreate() {
                    super.onCreate();
            HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
            thread.start();
    
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
        }
    
        @Override
        public void onStart(Intent intent, int startId) {
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
        }
    
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            onStart(intent, startId);
            return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
        }
    
        @Override
        public void onDestroy() {
            mServiceLooper.quit();
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
    
        protected abstract void onHandleIntent(Intent intent);
    }
    

    可以看到它在onCreate里面初始化了一个HandlerThread,关于HandlerThread的使用和源码 
    分析参考:Android HandlerThread 完全解析,看到这估计已经能猜到它的逻辑了:

    就是每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);就可以了。

    那么我们具体看一下源码,果然是这样,onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去。最后handleMessage中回调onHandleIntent(intent)。

    注意下:回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.

    如果传入的是-1则直接销毁。

    那么,当任务完成销毁Service回调onDestory,可以看到在onDestroy中释放了我们的Looper:mServiceLooper.quit()。

    ok~ 如果你的需求可以使用IntentService来做,可以尽可能的使用,设计的还是相当赞的。当然了,如果你需要考虑并发等等需求,那么可能需要自己去扩展创建线程池等。

  • 相关阅读:
    Advanced Configuration Tricks
    Reviewing the Blog Module
    Editing and Deleting Data
    Making Use of Forms and Fieldsets
    Understanding the Router
    SQL Abstraction and Object Hydration
    Preparing for Different Databases
    Java学习理解路线图
    Openstack学习历程_1_视频
    CentOS安装Nginx负载
  • 原文地址:https://www.cnblogs.com/vincentmax/p/6471961.html
Copyright © 2011-2022 走看看