一个优秀的Apps必然需要将耗时的操作如数据库操作/网络操作等放在其他线程(非UI),然后将结果发送至MainUI创建的Handler里面在UI显示结果(若需要的话).
而android的线程操作,除非需要非常及时,否则推荐使用HandlerThread而非Thread , HandlerThread与Handler联合使用,可能将Runnable队列化,亦就是说handler前一个post在runnable没运行完毕,后面的runnable一直在等待.
下面贴出一个例子,关于网络操作的,参数中可以选择onDone是否依然运行于子线程还是运行在MainUI,
public class NetUtil { protected static HandlerThread mRunThread = null; protected static Handler mHandler = null; static { mRunThread = new HandlerThread("com.freestyle.utils.NetUtil"); mRunThread.start(); mHandler = new Handler(mRunThread.getLooper()); } public static void close() { if (mRunThread != null) { mRunThread.quit(); } } static public void postUrlContent(final DefaultHttpClient httpClient, final String strUrl, final Object params, final int timeout, final String encoding, final RunnableWithValue onDone, final CookieStore cookiestore, final boolean keepalive, final OnHttpClientEvent clientEvent, boolean onDoneRunInThread) throws UnsupportedEncodingException { final Handler hd = onDoneRunInThread ? (new Handler(mRunThread.getLooper()) { @Override public void handleMessage(Message arg0) { onDone.v = (Bundle) arg0.getData(); onDone.run(); super.handleMessage(arg0); } }) : (new Handler() { @Override public void handleMessage(Message arg0) { onDone.v = (Bundle) arg0.getData(); onDone.run(); super.handleMessage(arg0); } }); mHandler.post(new Runnable() { @Override public void run() { try { Message msg = new Message(); msg.what = 1; OnDownLoadInterface od = onDone.onGetInterface(); if (params instanceof HashMap) { ArrayList<BasicNameValuePair> w_params = new ArrayList<BasicNameValuePair>(); for (Entry<String, Object> item : ((HashMap<String, Object>) params).entrySet()) { if (item.getValue().getClass().isArray()) { for (Object v : (Object[]) item.getValue()) { w_params.add(new BasicNameValuePair(item.getKey(), (String) v)); } } else { w_params.add(new BasicNameValuePair(item.getKey(), (String) item.getValue())); } } onDone.response = httpPost(httpClient, strUrl, w_params, timeout, cookiestore, encoding, od, keepalive, clientEvent); } else if (params instanceof String) { onDone.response = httpPost(httpClient, strUrl, params, timeout, cookiestore, encoding, od, keepalive, clientEvent); } else { // String // w_jsonStr=params==null?"":JsonUtils.jsonFromObject(params); onDone.response = httpPost(httpClient, strUrl, params, timeout, cookiestore, encoding, od, keepalive, clientEvent); } msg.setData(null); try { if (od != null && onDone.response.statusCode == HttpStatus.SC_OK) { if (!od.onFetchStreamsData()) { onDone.response.bytes = onDone.response._toBytes(); } } else { onDone.response.bytes = onDone.response._toBytes(); } } catch (Exception e) { // TODO Auto-generated catch block onDone.response.exception = e; e.printStackTrace(); } hd.sendMessage(msg); } catch (Exception e) { } } }); } }
onDoneRunInThread 参数决定handler hd的性质, onDoneRunInThread =true时,onDone后续例程则依然运行在mRunThread子线程中, 若为false则会在MainUI线程中运行, 因为new Handler()默认用的是MainUI 线程的looper.
================
另,需要一个线程安全的队列,我们需要用到ConcurrentLinkedQueue,它常用的方法有:
peek()- 从顶部取得数据,但不移除此记录,若队列为空则返回null
poll() - 同peek(),但差别是会同时移除此记录(队列记录数-1)
offer() - 在尾部添加数据,若超过容易会返回false
add() - 同offer()
===========================
关于Handler与Thread的关系,
Handler的创建可能还looper参数亦可能不带,若不还looper参数,则此handler为MainUI在looper服务,亦就是说它post的runnable或sendmessage都是在MainUI线程下运行的,
若比较耗时的操作,则应该避免用这种.
若带looper,则需要带对应thread的looper,比如上述例子中的:final Handler hd=onDoneRunInThread ? new Handler(mRunThread.getLooper()):new Handler();
先创建子线程mRunThread,然后mRunThread.start()后,再创建依赖于它的handler hd.给hd指定mRunThread的looper,则hd无论post runnable或sendmessage都在mRunThread线程中运行.
而为了直观,建议用post runnable代替sendmessage.