Android 处理程序与线程之间是否存在任何真正的性能影响?
关于Android 处理程序与线程之间是否存在任何真正的性能影响?,android,Android,关于线程与处理程序与异步任务的正确使用,存在许多问题。(如&) 这些问题很好地解决了何时使用什么的问题。我的问题更多的是在某些类型的情况下对性能的影响 例如,我经常看到其他人编写代码时使用线程,只是为了能够为将来安排一些代码执行。每当我看到这一点时,我本能地想重构代码,使用处理程序,只需发布延迟的可运行的 下面是一个例子,其中一个线程用于更新使用mediaplayer播放的某些媒体的seekbar,然后是我将使用的方法 我经常看到的: if (positionTracker != null &
线程
与处理程序
与异步任务
的正确使用,存在许多问题。(如&)
这些问题很好地解决了何时使用什么的问题。我的问题更多的是在某些类型的情况下对性能的影响
例如,我经常看到其他人编写代码时使用线程
,只是为了能够为将来安排一些代码执行。每当我看到这一点时,我本能地想重构代码,使用处理程序
,只需发布延迟的可运行的
下面是一个例子,其中一个线程用于更新使用mediaplayer
播放的某些媒体的seekbar,然后是我将使用的方法
我经常看到的:
if (positionTracker != null && positionTracker.isAlive()
&& !positionTracker.isInterrupted()) {
return;
}
positionTracker = new Thread(new Runnable() {
public void run() {
int currentPosition = 0;
int total = player.getDuration();
while (player != null && CurrentPosition < total) {
try {
Thread.sleep(1000);
currentPosition = player.getCurrentPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
if (someListener != null) {
someListener.onEvent();
}
}
}
}, "position tracker thread");
positionTracker.start();
Runnable trackPositionRunnable = new Runnable() {
@Override
public void run() {
currentPosition = player.getCurrentPosition();
if (someListener != null) {
someListener.onEvent();
mHandler.postDelayed(this, 1000);
}
}
};
mHandler.post(trackPositionRunnable);
显然,我更喜欢的方式是更容易阅读和更简洁但性能影响是什么?就性能而言,一种方法比另一种方法更好吗?如果是,原因是什么?正确性:您的第一个示例充满了危险,因为必须在具有自己的
循环器的线程上创建MediaPlayer
,来自任何其他线程的操作都可能导致错误。类似地,由于您的someListener.onEvent()
可能正在更新UI,因此最好知道如何将其发布到UI线程上的处理程序
性能:我没有提供任何度量,但在您的示例中,运行时成本是(线程切换)+(处理程序开销),而不是(处理程序开销)。因此,对于任何切换开销大于0的线程,线程的开销都会更高。另一方面,如果您的整个应用程序都是以您喜欢的风格编写的,并且您的任何代码都是缓慢和同步的,那么您只会让您的应用程序感觉滞后
这就是为什么任何可能缓慢或同步的东西都需要转向线程(或服务)风格,尽管感觉更复杂、更容易出错。您特定的MediaPlayer示例并不是一个完美的例子。每种方法都取决于您计划在该可运行环境中执行的操作,以及它是否有用。它们之间最大的区别在于你是否打算触摸UI。在安卓系统中,用户界面组件不能脱离用户界面线程(你的媒体播放器示例就是用原始线程打破这一规则)。因为这条规则会立即划分每个方法可以做什么和不能做什么。这些方法之间的性能差异可以忽略不计,因为运行后台作业所花费的时间将胜过它们之间的任何差异
处理程序通常使用另一个后台线程来执行中的逻辑,但这取决于由哪个线程构造处理程序。如果处理程序是在UI线程上构造的(响应对某些内容的回调),那么您的Runnable将在UI线程内运行,从而可以触摸UI组件。但是,如果您是在UI线程之外创建的,则发布到它的Runnables无法接触UI组件。在UI线程上创建的处理程序的缺点是,您没有在后台执行这些操作,因此,如果作业需要很长时间才能运行,它将锁定UI,直到完成为止。而从非UI线程运行的处理程序将修复锁定UI的任何问题。它们需要更多的工作来设置,并且您仍然需要处理如何安全地更新UI以响应您的后台作业(即,如果您想要更新UI,您仍然需要将另一个可运行的返回到UI线程)
原始线程不会锁定UI,因为它们独立于UI线程运行,但您不能在它们上触摸UI组件。这意味着您必须在UI线程上执行要更新UI的任何代码,这意味着需要编写更多代码才能让UI线程运行它。这可能非常复杂。由于使用原始线程的复杂性,应该真正避免使用它们
最常见的后台任务示例是等待服务器的响应。大多数库都会阻塞,直到服务器发送响应,这意味着您无法在UI线程上调用它们,否则,在服务器返回调用之前,您的用户将被阻止执行任何操作。它们不仅会被阻止,而且UI无法更新自身以显示微调器或以其他方式看起来是活动的。这是最好的推到一个背景线程。从技术上讲,处理程序和线程可以做到这一点,但必须专门构造处理程序,以便使用真正的后台线程
这就是AsyncTask胜过处理程序的地方,因为它同时执行真正的后台作业和UI更新。它有一个用于在后台执行一些长时间运行的操作的部分,还有一个用于在完成操作时从UI线程更新UI的部分。它甚至有一个可选的进度部分,因此您可以在任务运行时向UI提供任何中间进度。异步任务的缺点是它们必须有一个结束。继续运行以定期检查是否发生了某些事情、睡眠和检查更多情况的后台作业对AsyncTask模型不利。然而,这并不是说您不能使用处理程序定期启动AsyncTask,只是为了讨论的完整性,我提到了这一点
最后,使用原始线程并不是那么容易,甚至“更好”,因为处理程序几乎可以用更少的代码完成线程可以完成的任何事情。但是,处理程序很难确定Runnable在哪个线程上执行。通常是UI线程,从技术上讲,将其设置为使用非UI线程是很棘手的。这两个选项都存在UI更新问题,因为在真正的后台作业结束时,您必须进行额外的工作才能运行UI作业。AsyncTask确实是我做后台工作的首选方法。如果您处理线程,我建议您将处理程序与它一起使用:
Handler handle = new Handler();
Thread new Thread()
{
@Override
public void run()
{
try
{
handle.postDelayed(new Runnable()
{
@Override
public void run()
{
"your code goes here"
}
},delay);
}
catch(Exception e)
{
e.printStackTrace();
}
};
}
这样你就可以延迟e