最好使用几个AsyncTask或HandlerThread(管道线程)



在应用程序中有一个HandlerThread来执行不同的时间消耗操作,例如排序,甚至处理web/文件流,这是一种好方法吗?什么更好地用于这样的目的:几个AsyncTask、几个Thread或一个类似HandlerThreadhttp://hi-android.info/src/android/webkit/WebViewWorker.java.html?

必须将耗时的操作(网络、数据库访问…)委派给某些类型的工作线程。阻止主(UI)线程是不可接受的。

CCD_ 5是一个高级对象。它使用内部HandlerExecutor为您处理线程处理和线程间通信。它是为(非常)常见的在后台做某事并将结果推送到UI的情况而设计的。

直接使用HandlerHandlerThread(或事件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

顺便说一句,由于管道线程(也称为处理程序线程)一次执行一个任务,因此我必须为可能并行运行的任务使用不同的处理程序线程。

最新更新