1. 概述
对于开发中的一些耗时操作,比如上传多张图片、下载任务等,然后把 应用置于后台,自己干别的事情,此时Activity可能会被杀死,做法是可以直接交给Service去做,担心Service被杀死,可以设置前台Service;
对于Service执行耗时操作,有2种处理方式:
方式1:在 Service中开子线程;
方式2:用 IntentService;
2. IntentService
IntentService 继承于 Service,用于处理 异步请求,用 startService开启服务,完成任务后会自己自动关闭服务,并且请求是在子线程中完成的;
好处:
1>:不用自己 new Thread() 开线程;
2>:不用考虑什么时候关闭Service;
3. IntentService使用
效果图如下:
每点击一次按钮,就会创建一个上传任务,然后交给后台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;