我们为什么要使用aysntask或service而不是新线程

时间:2013-11-25 23:40:44

标签: android multithreading process android-asynctask android-service

在android中我们为什么要使用asyntask和service,而不是使用新的thread()并编写必要的后台功能?

我知道我们不应该运行长时间运行的操作,比如在mainthread即UI线程上从服务器下载文件。并且应该使用asynctask或服务。

但是为什么我们不能创建一个新的thread(){它最终是一个除主线程之外的新线程}并在该线程中编写必须长时间运行的操作。

谷歌为什么创建AsyncTask和服务而不建议使用常规的新主题()???

提前致谢

EDIT1: 可能是我不清楚我的问题或不确定,如果我,即使现在。帮助我。

我明白了,整点从

开始
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread 
为什么? 1. UI线程可以处理多少?我们如何确定断点?如何确定ANR点?我们可以追踪吗? 2.当服务组件处理长时间运行的操作时,为什么活动组件不能处理?

请记住,如果您确实使用某项服务,默认情况下它仍会在您的应用程序的主线程中运行,因此如果它执行密集或阻塞操作,您仍应在服务中创建新线程 http://developer.android.com/guide/components/services.html 以上陈述来自android文档。

3.如果我们如此担心主线程,我们是否可以立即开始新线程中的服务?不要误解我的问题3,我试图了解在主线程中启动服务的优势。默认情况下。

在上面的语句中,它是否表明主线程能够启动和处理服务的长时间运行操作负载?如果是这样,它与问题1相矛盾。

2 个答案:

答案 0 :(得分:8)

让我们看看你如何使用线程执行一项简单的任务。

第一步是使用Runnable创建一个Thread。像这样:

private void fetchResultsAsync() {
    Runnable runner = new Runnable() {

        @Override
        public void run() {
            List<String> results = fetchResultsFromWebServer();
        }
    };
    new Thread(runner).run();
}

问题是,我们需要显示结果,所以它实际上更像是这样:

private void fetchResultsAsync() {
    Runnable runner = new Runnable() {

        @Override
        public void run() {
            List<String> results = fetchResultsFromWebServer();
            workFinished(results);
        }
    };
    new Thread(runner).run();
}
private void workFinished(List<String> results) {
    // show the results on the UI
}

它看起来不错,但是存在问题;回调方法(workFinished)必须更新UI。如果我们从任何非主线程执行此操作,将会出现大问题。我们需要一种线程安全的方法来调用该方法,这就是Handlers的用途。我们还提出了一种更新进度的方法,这是非常常见的。代码现在看起来像这样:

private final Handler myHandler = new Handler();
private void fetchResultsAsync() {
    Runnable runner = new Runnable() {

        @Override
        public void run() {
            List<String> results = fetchResultsFromWebServer();
            workFinished(results);
        }
    };
    new Thread(runner).run();
}
private void showProgress(int result) {
    myHandler.post(new Runnable() {
        @Override
        public void run() {
            // update a progress bar here
        }
    });
}
private void workFinished(final List<String> results) {
    myHandler.post(new Runnable() {
        @Override
        public void run() {
            // show the results on the UI
        }
   });
}

将此与使用AsyncTask的实现进行比较:

private void fetchWithTask() {
    new AsyncTask<Void, Integer, List<String>>() {

        @Override
        protected List<String> doInBackground(Void... params) {
            return fetchResultsFromWebServer();
        }

        @Override
        protected void onPostExecute(List<String> strings) {
            // show the results on the UI
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            // update a progress bar here
        }
    }.execute();
}

代码行并没有多大差别,但需要发生的事情和地点更加明显。它可以保护您免受令人讨厌的错误,例如忘记在Runnable中包含UI触摸代码,该代码必须发布到UI-Thread拥有的Handler。

现在假设您有几种不同类型的小背景任务需要执行。从错误的后台线程中调用错误的showProgress或workFinished方法会非常容易,因为你必须自己将所有这些部分插在一起。

在使用Handler的默认构造函数时,潜伏着一个非常讨厌的bug。如果在运行时期间非UI线程首次引用包含类,则Handler将属于该Thread。 AsyncTask隐藏总是在正确的线程上做事情。这很难抓住!

乍一看AsyncTasks看起来并不是很有用,但回调管道是他们真正在黑桃中得到回报的地方。

答案 1 :(得分:1)

“而不是使用新的线程()并编写必要的后台功能?”

为什么要重写后台功能? AsyncTask为你做到了。正如njk2所提到的,Service并不是一个公平的比较,尽管IntentService会自动在onHandleIntent()中为你创建一个新线程。

编辑:要回答其他问题,阻止UI线程,将阻止所有用户交互,应用程序将显示为“冻结”。绝对不是我们想要做的事情。