在Android中有两种线程UI线程和子线程,我们都很清楚如果在UI线程进行耗时处理的话就容易引起ANR、如果是一个网络请求放在UI线程处理的话也会引起NetworkOnMainThreadExeception异常,对于这些情况我们就需要开启新的线程来处理。
HandlerThread使用
首先看名字我们就知道肯定Handler跑不了确实也是如此,在此我们需要一个Handler来处理异步需求,其中需求只是简单的一个网络请求。
class TestHandler extends Handler {
public TestHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
try {
URL url = new URL("http://www.baidu.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream is = connection.getInputStream();
String result = null;
String input;
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while ((input = reader.readLine()) != null) {
result += input;
}
Log.w("TestHandler", result);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
定义完成Handler之后我们的HandlerThread就该初始化了
HandlerThread handlerThread = new HandlerThread("test_thread");
handlerThread.start();
TestHandler handler = new TestHandler(handlerThread.getLooper());
handler.sendEmptyMessage(0);
HandlerThread的工作原理其实很简单,首先一个HandlerThread是extends自Thread所以他是一个线程,那么我们Handler在这个线程中初始化就会运行在HanderThread这个线程中,Handler中的Looper就会轮询该线程对应的Message从而回调handlerMessage方法中去所以整个流程都是在子线程中运行从而起到跟Thread一样的异步效果。
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
这是一段HandlerThread的源码,所以Handler在初始化之前必须保证HandlerThread已经调用了start,因为如果没start那么Looper就没有执行prepared会引起异常。
最后,我们需要记得当不需要的时候记得调用HandlerThread.quit()方法移除可能未完成的操作避免内存泄露等危险养成一种良好的习惯。
IntentService的使用
IntentService的本质是一个Service内部使用HandlerThread来处理异步请求,每一次请求完成之后会自我的stopSelf来停止Service,所以很适合用于后台完成异步请求相比Service整体性能更优。
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
我们可以看到在onCreate中完成了HandlerThread初始化,这时候mServiceHandler就开始监听startService。
Intent intent = new Intent();
intent.setClass(MainActivity.this, TestIntentService.class);
intent.putExtra("content", "http://www.baidu.com");
startService(intent);
我们在UI线程通过跟启动Service一样通过intent启动一个IntentService会在onStart把intent转到sServiceHandler中去。
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
再看看下ServiceHandler的源码:
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);
}
}
可以看到在handleMessage调用onHandleIntent这个抽象方法可见为什么我们新建一个IntentService需要重写onHandleIntent方法且在里面处理事务就好。
下面一段测试代码,通过intent把请求的地址传进来然后在IntentService执行一次请求:
public class TestIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public TestIntentService() {
super("TestIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
String urlName = intent.getStringExtra("content");
try {
URL url = new URL(urlName);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream is = connection.getInputStream();
String result = null;
String input;
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while ((input = reader.readLine()) != null) {
result += input;
}
Log.w("TestIntentService", result);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在ServiceHandler中我们可以看见执行完onHandleIntent后会调用stopSelf(msg.arg1)来stop这个Service,当然如果这个时候还有其他的消息还未处理完成则会等待其他完成后再执行stopSelf。