Java Android-创建同步计时器
我知道计时器的工作原理是让线程睡眠x个时间,但我想知道是否有某种计时器不在非UI线程的线程上运行。我曾考虑过使用一个循环,以毫秒为单位不断比较系统时间,但我想将其作为最后手段,因为它似乎不是很有效 编辑: 堆栈跟踪:Java Android-创建同步计时器,java,android,timer,sync,Java,Android,Timer,Sync,我知道计时器的工作原理是让线程睡眠x个时间,但我想知道是否有某种计时器不在非UI线程的线程上运行。我曾考虑过使用一个循环,以毫秒为单位不断比较系统时间,但我想将其作为最后手段,因为它似乎不是很有效 编辑: 堆栈跟踪: 07-25 14:38:38.037 22108-22124/com.example.myapp E/ViewRootImpl﹕ com.example.myapp.Main : Only the original thread that created a view hiera
07-25 14:38:38.037 22108-22124/com.example.myapp E/ViewRootImpl﹕ com.example.myapp.Main : Only the original thread that created a view hierarchy can touch its views.
java.lang.RuntimeException
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6355)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:929)
at android.view.ViewGroup.invalidateChildFast(ViewGroup.java:4466)
at android.view.View.invalidateViewProperty(View.java:11112)
at android.view.View.setTranslationY(View.java:10472)
at android.view.View.setY(View.java:10400)
at com.example.myapp.Player.update(Player.java:29)
at com.example.myapp.Main.update(Main.java:70)
at com.example.myapp.Main.access$000(Main.java:15)
at com.example.myapp.Main$1.run(Main.java:33)
at java.util.Timer$TimerImpl.run(Timer.java:284)
相关代码:
if (!onGround){
playerVisual.setY(playerVisual.getY() + this.gravity);
}
if (playerVisual.getY() >= this.main.getDevice().getHeight() - 10){
this.onGround = true;
}
else {
this.onGround = false;
}
playerVisual是一个图像视图,如果您想知道的话。您基本上希望阻止当前线程/等待条件-好的 有几个选项-最简单的是使用: 另一个选择是: 当然:这有点滥用这些类,但它工作得很完美。 你甚至可以使用,但由于一个对象可以接收“虚假唤醒”,你必须处理这些-这并不总是像一开始看起来那么容易 基本上,您可以使用几乎所有的机制来可靠地“等待”某件事情,直到您的下一个时间片准备就绪(因此:某件事情超时)并继续在您的循环中
在Java以外的语言中,它可以(可靠地)暂停/暂停当前线程一段固定的时间——这甚至更好,但它打破了许多编程范例,可能很难理解;最好不要接触线程本身,除非你真的有经验并且对这些事情有很多了解,阻止方法调用几乎总是最好的选择,即使这意味着要编写几行额外的代码。你基本上想要阻止当前线程/等待一个条件-好的 有几个选项-最简单的是使用: 另一个选择是: 当然:这有点滥用这些类,但它工作得很完美。 你甚至可以使用,但由于一个对象可以接收“虚假唤醒”,你必须处理这些-这并不总是像一开始看起来那么容易 基本上,您可以使用几乎所有的机制来可靠地“等待”某件事情,直到您的下一个时间片准备就绪(因此:某件事情超时)并继续在您的循环中
在Java以外的语言中,它可以(可靠地)暂停/暂停当前线程一段固定的时间——这甚至更好,但它打破了许多编程范例,可能很难理解;最好不要触碰线程本身,除非你真的有经验并且对这些事情有很多了解,阻止方法调用几乎总是最好的选择,即使这意味着要编写几行额外的代码。这是一个从计划任务更新GUI的解决方案。使用处理器而不是计时器
final Handler handler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
handler.postDelayed(myRunnable, 1000); //1 second
/*UPDATE GUI*/
update();
}
};
myRunnable.run();
这是一个从计划任务更新GUI的解决方案。使用处理器而不是计时器
final Handler handler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
handler.postDelayed(myRunnable, 1000); //1 second
/*UPDATE GUI*/
update();
}
};
myRunnable.run();
这是一个基于AsyncTask的解决方案:
class AsyncTimer extends AsyncTask<Void, Void, Void>
{
boolean alive = true;
long startMS;
long intervalMS;
MainActivity activity;
public AsyncTimer(long startMS, long intervalMS, MainActivity activity)
{
this.startMS = startMS;
this.intervalMS = intervalMS;
this.activity = activity;
}
protected Void doInBackground(Void... params)
{
try
{
Thread.sleep(startMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
while (alive)
{
try
{
alive = activity.updateUI();
Thread.sleep(intervalMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
}
return null;
}
}
这是一个基于AsyncTask的解决方案:
class AsyncTimer extends AsyncTask<Void, Void, Void>
{
boolean alive = true;
long startMS;
long intervalMS;
MainActivity activity;
public AsyncTimer(long startMS, long intervalMS, MainActivity activity)
{
this.startMS = startMS;
this.intervalMS = intervalMS;
this.activity = activity;
}
protected Void doInBackground(Void... params)
{
try
{
Thread.sleep(startMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
while (alive)
{
try
{
alive = activity.updateUI();
Thread.sleep(intervalMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
}
return null;
}
}
Swing有一个
Timer
类,该类在Swing的主线程上运行事件(该线程不是main
运行的线程)@immibis有没有不使用Swing的方法来执行此操作?取决于您尝试执行的操作。没有单一简单方法的原因是:当计时器用完时,如果线程忙于做其他事情,会发生什么?您试图解决的实际问题是什么?为什么您关心计时器线程不是主线程?好的。然后在你的问题上添加android标记,将“主线程”替换为“UI线程”(这两个是完全不同的事情),为你的问题添加相关的代码,以及完整的堆栈跟踪,这样我们可以帮助你理解你做错了什么,以及如何修复它。Swing有一个Timer
类,可以在Swing的主线程上运行事件(它不是运行在上的main
)@immibis有没有一种不使用Swing的方法可以做到这一点?这取决于你正在尝试做什么。没有单一简单方法的原因是:当计时器用完时,如果线程正在忙于做其他事情会发生什么?你试图解决的实际问题是什么?为什么你关心计时器线程不是主线程?好的。然后添加android标记您的问题,将“主线程”替换为“UI线程”(这两个是完全不同的事情),将相关代码添加到您的问题中,并添加完整的堆栈跟踪,以便我们可以帮助您了解您做错了什么,以及如何修复它。这是有效的:)但是有没有一种方法可以让它重复而不仅仅是延迟?@ReadySetPawn一种方法是做一个堆栈。这是可行的:)但是有没有一种方法可以让它重复而不仅仅是延迟?@ReadySetPawn一种方法是做一个堆栈。
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
...
new AsyncTimer(0, 1000, this).execute();
}
public boolean updateUI()
{
Log.d("Timer", "tick");
...
return true;
}