在应用程序中有一个HandlerThread
来执行不同的时间消耗操作,例如排序,甚至处理web/文件流,这是一种好方法吗?什么更好地用于这样的目的:几个AsyncTask
、几个Thread
或一个类似HandlerThread
http://hi-android.info/src/android/webkit/WebViewWorker.java.html?
您必须将耗时的操作(网络、数据库访问…)委派给某些类型的工作线程。阻止主(UI)线程是不可接受的。
CCD_ 5是一个高级对象。它使用内部Handler
和Executor
为您处理线程处理和线程间通信。它是为(非常)常见的在后台做某事并将结果推送到UI的情况而设计的。
直接使用Handler
和HandlerThread
(或事件Thread
)可以提供更大的灵活性,但代价是更复杂的代码和一些微妙的陷阱(例如,如何泄露上下文:Handlers&Inner Classes)。
您可以选择串行或并行执行任务。HandlerThread
会将它们序列化。对于AsyncTask
,它取决于Android版本(但这可以被覆盖)。每次创建Thread
可能会导致并发线程数量过多。
简而言之,它们都很好,因为您没有锁定UI。
更长的答案,主要取决于偏好。我使用的解决方案是基本线程和处理程序的组合。由于基本线程不在主UI线程上运行,因此通常当一个线程完成时,您需要报告或更新设置。这是当我使用一个处理程序和一组易于阅读的键时。因此,我可以访问任何视图,并根据需要进行更改。请记住,声明并保留对视图的全局引用,根据需要进行分配和使用,并在完成后丢弃是不明智的。
private static final int SET_LOADING = 0;
private static final int SET_TEXT = 1;
private Handler mEventHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// if stmts||switch - personal preference
if(msg.what == SET_LOADING ){
setLoading(((Boolean) msg.obj));
}else if(msg.what == SET_TEXT){
setText(msg.arg1, (String) msg.obj);
}
super.handleMessage(msg);
}
}
/**
* set the text of a textbox
* @param id int - R.id.{...}
* @param text String
*/
private void setText(int id, String text){
TextView t = ((TextView) findViewById(id));
if(t != null){
t.setText(text);
}
}
/**
* is the UI currently loading something? lock controls
* @param isLoading boolean
*/
private void setLoading(boolean isLoading){
mIsLoading = isLoading;
if(isLoading){
(SomeSpinningProgressBar).setVisibility(View.VISIBLE);
}else{
(SomeSpinningProgressBar).setVisibility(View.INVISIBLE);
}
}
public void onClick(View v) {
/**
* some button that triggers a database connection
*/
if( v.getId() == R.id.some_button ) {
/** basic thread */
new Thread(new Runnable() {
public void run() {
if(this.hasWebConnection()){
/** tell the UI thread to start loading */
mEventHandler.sendMessage(
mEventHandler.obtainMessage(SET_LOADING, 0, 0, true));
// do work...
if(someErrorOccuredBoolean){
/** report to user of an error */
mEventHandler.sendMessage(
mEventHandler.obtainMessage(SET_TEXT, R.id.some_textview, 0, "There was an error!"));
}
/** tell the UI thread to stop loading */
mEventHandler.sendMessage(
mEventHandler.obtainMessage(SET_LOADING, 0, 0, false));
}else{
mEventHandler.obtainMessage(SET_TEXT, R.id.some_textview, 0, "No internet found!!"));
}
}
}
);
}
}
有时,特别是当您使用本机库时,您必须在用于库初始化的同一线程上调用函数。原因是库可能会将某些内容存储到线程本地存储中。在这种情况下,AsyncTask
不是一个选项。
无论系统库是否使用线程本地存储,以及将来是否会使用它。。。好吧,你明白我的观点了:为了安全起见,当我使用JNI库时,我更喜欢只使用一个线程,这意味着没有AsyncTask
。
顺便说一句,由于管道线程(也称为处理程序线程)一次执行一个任务,因此我必须为可能并行运行的任务使用不同的处理程序线程。