在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相矛盾。
答案 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线程,将阻止所有用户交互,应用程序将显示为“冻结”。绝对不是我们想要做的事情。