美文网首页
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