我知道计时器通过使线程休眠x个时间来工作但是我想知道是否存在某种不在UI线程的线程上运行的计时器。我想过使用一个不断比较系统时间的循环(以毫秒为单位),但是我想把它作为最后的手段,因为它看起来效率不高。
编辑:
堆栈跟踪:
val someValue: String = "key"
val someOtherValue: Double = 0.1
val P: Map[String, Map[String, Map[String, Double]]] =
HashMap("a" -> HashMap(
"aa" -> HashMap(
"aaa" -> 0.25,
"aab" -> 1 // implicitly converted to Double
),
"ab" -> HashMap(
"aba" -> 0.2,
"abb" -> 0.8)
),
"b" -> HashMap(
"ba" -> HashMap(
"baa" -> -0.3,
"bab" -> -0.4,
"bac" -> -0.2
),
"bb" -> HashMap(
// would not compile, though it would compile in the original example
// messing up the result type completely and good luck finding this
// with the original formatting
/* someOtherValue -> someValue, */
"bba" -> 0.3,
"bbb" -> 0.4,
"bbc" -> 0.4
)
),
"c" -> HashMap(
"ca" -> HashMap(
"caa" -> 0.2,
"cab" -> 0.001
),
"cb" -> HashMap() // Map[String, Double] inferred
)
)
val m = P("a")("aa")("aab") // -> 1.0
val m2 = P("a")("ab")("aba") // -> 0.2
相关代码:
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)
如果你想知道,playerVisual是一个ImageView。
答案 0 :(得分:1)
这是一个基于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;
}
}
在MainActivity中使用它:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
...
new AsyncTimer(0, 1000, this).execute();
}
public boolean updateUI()
{
Log.d("Timer", "tick");
...
return true;
}
答案 1 :(得分:0)
这是从计划任务更新GUI的解决方案。使用Handler而不是Timer
final Handler handler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
handler.postDelayed(myRunnable, 1000); //1 second
/*UPDATE GUI*/
update();
}
};
myRunnable.run();
答案 2 :(得分:-1)
你基本上想要阻止当前线程/等待条件 - 好吧 有几种选择 - 最简单的方法是使用Semaphore:
final Semaphore semaphore = new Semaphore(0); //not available at first
try
{
semaphore.tryAcquire(1, TimeUnit.SECONDS); //block for 1 second since it isnt available
}
catch(InterruptedException ex)
{
//do something sensible here
}
另一个选项是CountDownLatch:
final CountDownLatch latch = new CountDownLatch(1); //1 latch available
try
{
latch.await(1, TimeUnit.SECONDS) //since currently one latch is available this will timeout
}
catch(InterruptedException ex)
{
//do something sensible here
}
当然:这有点滥用这些课程,但它的工作完美无缺。 你甚至可以使用Object.wait但是因为一个对象可以接收到#e;的虚假唤醒&#34;你将不得不处理那些 - 这并不像最初看起来那么容易。
基本上,您可以使用几乎任何机制,让您可靠地等待&#34;关于某事 - 直到你的下一个时间片准备好被采取(因此:某事物超时)并继续你的循环。
在Java之外的语言中,它可以(可靠地)暂停/暂停当前线程一段固定的时间 - 这甚至更好但是它打破了相当多的编程范例并且很难理解;最好不要触及线程本身,除非你真正经验丰富且对这些事情有很多了解,阻塞方法调用几乎总是最好的选择,即使这意味着编写一些额外的代码行。