Android之IntentService

发布时间 2023-07-12 14:40:54作者: 邢帅杰

IntentService,可以看做是Service和HandlerThread的结合体,在完成了使命之后会自动停止,适合需要在工作线程处理UI无关任务的场景。
IntentService 是继承自 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作。
当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。
如果启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。
下面是一个例子,点击开始启动一个IntentService去更新进度条,更新完毕IntentService会自动结束。如果多次点击开始,就会执行多遍,多遍执行完之后IntentService才会执行onDestroy方法。

package com.jay.services;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.jay.myandroidtestapp.IntentServiceActivity;

/**
 * 启动之后会先执行构造方法,然后执行onCreate方法,再到onHandleIntent方法。
 * 在onHandleIntent让进度自增,每次自增睡眠50ms并向Activity发送广播并传递进度的数据。
 * */
public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public MyIntentService(String name) {
        super(name);
    }
    public MyIntentService() {
        super(TAG);
    }
    /**
     * 是否正在运行
     */
    private boolean isRunning;

    /**
     * 进度
     */
    private int count;

    /**
     * 广播
     */
    private LocalBroadcastManager mLocalBroadcastManager;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate");
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.i(TAG, "onHandleIntent");
        try {
            Log.d(TAG, "onHandleIntent 线程运行中...");
            Thread.sleep(1000);
            isRunning = true;
            count = 0;
            while (isRunning) {
                count++;
                if (count >= 100) {
                    isRunning = false;
                }
                Thread.sleep(50);
                Log.d(TAG, "onHandleIntent 线程运行中...");
                sendThreadStatus("线程运行中...", count);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送进度消息
     */
    private void sendThreadStatus(String status, int progress) {
        Intent intent = new Intent(IntentServiceActivity.ACTION_TYPE_THREAD);
        intent.putExtra("status", status);
        intent.putExtra("progress", progress);
        mLocalBroadcastManager.sendBroadcast(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "线程结束运行..." + count);
    }
}

启动之后会先执行构造方法,然后执行onCreate方法,再到onHandleIntent方法。在onHandleIntent让进度自增,每次自增睡眠50ms并向Activity发送广播并传递进度的数据。
IntentServiceActivity

package com.jay.myandroidtestapp;

import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.jay.services.MyIntentService;
import com.jay.utils.MyBroadcastReceiver;

public class IntentServiceActivity extends AppCompatActivity {

    private String TAG = "IntentServiceActivity";
    /**
     * 状态文字
     */
    private TextView tv_status;

    /**
     * 进度文字
     */
    private TextView tv_progress;

    /**
     * 进度条
     */
    private ProgressBar progressbar;

    private Button btn_start;

    private LocalBroadcastManager mLocalBroadcastManager;
    private MyBroadcastReceiver mBroadcastReceiver;
    public final static String ACTION_TYPE_THREAD = "action.type.thread";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_service);

        tv_progress = findViewById(R.id.tv_progress);
        tv_status = findViewById(R.id.tv_status);
        progressbar = findViewById(R.id.progressbar);
        btn_start = findViewById(R.id.btn_start);
        btn_start.setOnClickListener(myOnClickListener);

        //注册广播
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
        mBroadcastReceiver = new MyBroadcastReceiver(tv_status, tv_progress, progressbar,this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_TYPE_THREAD);
        mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

        initView();
    }

    public void initView() {
        tv_status.setText("线程状态:未运行");
        progressbar.setMax(100);
        progressbar.setProgress(0);
        tv_progress.setText("0%");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //注销广播
        mLocalBroadcastManager.unregisterReceiver(mBroadcastReceiver);
    }

    public View.OnClickListener myOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_start:
                    Log.d(TAG, "onHandleIntent 线程运行中...");
                    Intent intent = new Intent(IntentServiceActivity.this, MyIntentService.class);
                    startService(intent);
                    break;
            }
        }
    };
}

点击开始按钮,会启动MyIntentService。mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter)注册广播,接收广播消息和数据,并时刻更改进度条进度。
自定义广播

package com.jay.utils;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.jay.myandroidtestapp.IntentServiceActivity;

/**
 * 自定义广播接收器
 * */
public class MyBroadcastReceiver extends BroadcastReceiver {
    public static final String TAG = "MyBroadcastReceiver";/**
     * 状态文字
     */
    private TextView tv_status;

    /**
     * 进度文字
     */
    private TextView tv_progress;

    /**
     * 进度条
     */
    private ProgressBar progressbar;

    private Activity curActivity;

    public MyBroadcastReceiver(){}
    public MyBroadcastReceiver(TextView tv_status, TextView tv_progress, ProgressBar progressbar,Activity curActivity){
        this.progressbar = progressbar;
        this.tv_progress = tv_progress;
        this.tv_status = tv_status;
        this.curActivity = curActivity;
    }
    @Override
    public void onReceive(Context context, Intent intent) {switch (intent.getAction()) {
            case IntentServiceActivity.ACTION_TYPE_THREAD:
                curActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //更改UI
                        int progress = intent.getIntExtra("progress", 0);
                        tv_status.setText("线程状态:" + intent.getStringExtra("status"));
                        progressbar.setProgress(progress);
                        tv_progress.setText(progress + "%");
                        if (progress >= 100) {
                            tv_status.setText("线程结束");
                        }
                    }
                });
                break;
        }
    }
}

注册MyIntentService
<service android:name="com.jay.services.MyIntentService" tools:ignore="Instantiatable"></service>
IntentService继承自Service,内部有一个HandlerThread对象。
在onCreate的时候会创建一个HandlerThread对象,并启动线程。紧接着创建ServiceHandler对象,ServiceHandler继承自Handler,用来处理消息。ServiceHandler将获取HandlerThread的Looper就可以开始正常工作了。
每启动一次onStart方法,就会把数消息和数据发给mServiceHandler,相当于发送了一次Message消息给HandlerThread的消息队列。mServiceHandler会把数据传个onHandleIntent方法,onHandleIntent是个抽象方法,需要在IntentService实现,所以每次onStart方法之后都会调用我们自己写的onHandleIntent方法去处理。处理完毕使用stopSelf通知HandlerThread已经处理完毕,HandlerThread继续观察消息队列,如果还有未执行玩的message则继续执行,否则结束。
IntentService内部的HandlerThread 继承自 Thread,内部封装了 Looper,在这里新建线程并启动,所以启动 IntentService 不需要新建线程。
IntentService 中使用的 Handler、Looper、MessageQueue 机制把消息发送到线程中去执行的,所以多次启动 IntentService 不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行,而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
来源:https://blog.csdn.net/b1480521874/article/details/94987641/