3分钟让你清楚HandlerThread和IntentServi
HandlerThread概述
HandlerThread是Thread的子类,但是HandlerThread可以处理消息.
我们知道Handler是用来异步更新UI的,用来做线程间的通信的,更新UI时就是子线程与UI主线程之间的通信,那么如果想在子线程也处理消息.我们自己可以使用Thread + Handler
再调用Looper.prepare()
和Looper.loop()
来实现.所以Google为我们提供了封装好的HandlerThread
类来实现子线程与子线程通信,可以在子线程中处理消息.
HandlerThread的构造
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
HandlerThread的简单使用
1.创建一个HandlerThread对象,并且start跑起来
mHandlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
2.创建一个Handler对象来处理消息,但是Looper对象是mHandlerThread.getLooper()返回的线程所对应的Looper
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "收到消息");
}
};
3.创建一个线程,并且模拟耗时操作,然后发送消息,mHandler接受到消息,就在子线程中处理消息了
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(1000);//模拟耗时操作
mHandler.sendEmptyMessage(0);
}
}).start();
4.在不使用的情况下要释放mHandlerThread,防止浪费资源,内存泄露.因为mHandlerThread调用了Looper.loop,就是一个无限循环,如果不主动调用quit
或者quitSafely
是会一直阻塞等待消息.
mHandlerThread的run()方法
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
终止mHandlerThread线程的执行..
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
IntentService概述
在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activity就很可能会被杀死,所以可以考虑将上传操作交给Service去做,如果担心Service被杀,还能通过设置startForeground(int, Notification)方法提升其优先级。
在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,而自己去管理Service的生命周期以及子线程并非是个优雅的做法;所以Android给我们提供了 IntentService
这个类
IntentService是一个继承Service的一个类,用来处理异步的请求。你可以通过startService(Intent)来提交请求,当完成所有的任务以后会自行关闭
使用了IntentService最起码有两个好处,一是不需要自己去new Thread了;另外不需要考虑在什么时候关闭该Service.他会自动关闭
IntentService的简单使用
在AndroidManifest中注册,然后就当普通的Service使用..
模拟一个多个图片上传的例子
每当我们点击一次按钮,会将一个任务交给后台的Service去处理,后台的Service每处理完成一个请求就会反馈给Activity,然后Activity去更新UI。当所有的任务完成的时候,后台的Service会退出,不会占据任何内存。
Activity代码
public class IntentServiceActivity extends AppCompatActivity implements View.OnClickListener {
public static final String UPLOAD_RESULT = "UPLOAD_RESULT";
private LinearLayout mLyTaskContainer;
//创建一个广播,接收到消息就更新UI
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);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
mLyTaskContainer = (LinearLayout) findViewById(R.id.id_ll_taskcontainer);
findViewById(R.id.add_task).setOnClickListener(this);
registerReceiver();
}
private void handleResult(String path) {
TextView tv = (TextView) mLyTaskContainer.findViewWithTag(path);
tv.setText(path + " upload success ~~~ ");
}
private void registerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(UPLOAD_RESULT);
registerReceiver(uploadImgReceiver, filter);
}
int i = 0;
private void addTask() {
...
//这里调用UploadImgService去做后台耗时操作,上传图片
UploadImgService.startUploadImg(this, path);
...
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(uploadImgReceiver);
}
@Override
public void onClick(View v) {
addTask();
}
}
点击事件的时候,调用addTask
然后调用UploadImgService.startUploadImg(this, path);
启动UploadImgService.去模拟耗时网络请求.
UploadImgService代码
public class UploadImgService extends IntentService {
private final String TAG = "UploadImgService";
private static final String ACTION_UPLOAD_IMG = "UPLOAD_IMAGE";
public static final String EXTRA_IMG_PATH = "IMG_PATH";
public UploadImgService() {
super("UploadImgService");//创建HandlerThread的时候用来作为线程名字
}
//在Service的onStart时候回调
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: ");
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);//成功,发送广播通知接收者更新UI
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//这里是启动UploadImgService 服务
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);
}
}
直接startService() 启动UploadImgService服务,然后在onHanderIntent方法里面就可以直接去直接网络耗时请求操作了,不需要额外创建一个线程new Thread
来执行耗时操作了.
UploadImgService
在前面IntentServiceActivity
中被点击按钮启动后的调用方法顺序:
先是执行onStart
方法,在onStart
被执行就会马上执行onHanderIntent
方法,过了3秒,任务执行完了,就会自动关闭线程,执行了onDestroy
方法
IntentService源码解析
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(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
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;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
IntentService
是一个抽象类,子类必须实现onHandleIntent()方法,在被启动服务走到onCreate
的时候,会创建一个HandlerThread
,并且调用start
方法启动HandlerThread
.然后获取到自己线程所在的Looper
对象,初始化了ServiceHandler
成员变量.....
在onStart
的时候,就会调用mServiceHandler
的sendMessage(msg)
方法发送一个消息
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
mServiceHandler
处理消息的时候,会调用onHandleIntent
方法,然后调用stopSelf(msg.arg1)
来尝试停止服务,stopSelf(int startId)
会等待所有的消息都处理完毕之后才会终止服务,如果当前是最后一个任务,执行完了就会终止服务,如果不是最后一个任务,则等待任务执行完成再终止.