我正在使用AsynchTask来托管一个无限运行的模拟器,并在每个模拟步骤后发布结果。
将背景中的模拟循环限制在最高25Hz,并且仅使用结果调用javascript函数,它可以正常运行"罚款"。
除了在浏览器中更新webgl模型,看起来足够快,我还有两件事要从Android UI更新:FPS指标和带有表示某些值的TextViews的面板。如果我们忘记了FPS:
onProgressUpdate()函数已限制为以25Hz调用,以刷新模型。现在我使用另一个时间变量来限制在此方法中调用另一个更新UI面板textViews的方法。它限制在1Hz,低于我实际想要的但足够快的信息类型。该方法尽可能干净,所有视图都先前加载到一个变量,我每次都不加载它们。
效果是什么:看起来像更新5个textViews需要一秒钟所有的UI冻结,触摸动作非常滞后......
我通过以下方式降低了后台任务的优先级:
@Override
protected Boolean doInBackground(ModelSimulation... params) {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
...
在doInBackground方法的末尾使用了Thread.yield()。这改善了我所解释的行为,没有这些命令,行为甚至更糟。
我的问题是:
- 如果不是使用后台任务而是使用处理程序和我自己的线程,我会减少更多优先级吗?
- 服务会改善UI的行为吗?
- 为什么更新5个textViews需要花费这么长时间才能调用最终必须使用gpu更改webgl模型的javascript函数?
- Android没有准备好动态应用吗?像测试传感器的应用程序如何更快地更新UI?因为没有像textViews这样的标准组件? (比浏览器比textView更快)
注意:即使减少刷新限制,每次更新HUD时都会产生延迟效果。实际上我谈的是5个textViews,但只更新FPS指示器会产生相同的暂停。看起来必须切换到UI线程的唯一事实已经消耗了这段时间。
编辑1:
@Override
protected Boolean doInBackground(ModelSimulation... params) {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
if(simulator.getSimulatorStatus().equals(SimulatorStatus.Connected)){
try {
while (true){
//TODO Propagate
long dur = (System.nanoTime()-time_tmp_data);
if(dur<Parameters.Simulator.min_hud_model_refreshing_interval_ns){
try {
long sleep_dur = (Parameters.Simulator.min_hud_model_refreshing_interval_ns-(System.nanoTime()-time_tmp_data))/1000000;
if(sleep_dur>0){
Thread.sleep(sleep_dur);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
time_tmp_data = System.nanoTime();
SpacecraftState sstate = propagate();
int progress = (int)((extrapDate.durationFrom(finalDate)/mission.sim_duration)*100);
if(sstate!=null){
SimResults results = new SimResults(sstate, progress);
simulator.getSimulationResults().updateSimulation(results.spacecraftState, results.sim_progress);
publishProgress();
}
if(isCancelled())
break;
Thread.yield();
}
} catch (OrekitException e) {
// TODO Auto-generated catch block
e.printStackTrace();
simulator.showMessage(simulator.getContext().getString(R.string.sim_orekit_prop_error)+": "+e.getMessage());
}
}
return true;
}
@Override
protected void onProgressUpdate(Void... values) {
//Update model by push
simulator.getSimulationResults().pushSimulationModel();
//Update GUI HUD
if(time_tmp_gui==0 || (System.nanoTime()-time_tmp_gui)>Parameters.Simulator.min_hud_panel_refreshing_interval_ns){
time_tmp_gui = System.nanoTime();
simulator.getSimulationResults().updateHUD();
}
}
如果我评论线模拟器.getSimulationResults()。updateHUD();或直接该方法的内容,它工作&#34;罚款&#34;。此方法仅更改一些textviews文本:
public synchronized void updateHUD(){
//Log.d("Sim",System.currentTimeMillis()+": "+"pre update gui 1");
activity.runOnUiThread( new Runnable() {
@SuppressLint("ResourceAsColor")
public void run() {
if(view != null){
if(panel_time != null)
panel_time.setText(info.time.replace("T", " "));
if(panel_progress != null)
panel_progress.setProgress(info.progress);
if(panel_vel != null){
panel_vel.setText("Vel. "+String.format("%.2f", info.velocity)+" Km/s");
if(info.velocity>config.limit_velocity)
panel_vel.setTextColor(activity.getResources().getColor(R.color.panel_limit));
else
panel_vel.setTextColor(activity.getResources().getColor(R.color.panel_value));
}
if(panel_accel != null){
panel_accel.setText("Accel. "+String.format("%.2f", info.acceleration)+" Km/s2");
if(info.acceleration>config.limit_acceleration)
panel_accel.setTextColor(activity.getResources().getColor(R.color.panel_limit));
else
panel_accel.setTextColor(activity.getResources().getColor(R.color.panel_value));
}
if(panel_radium != null)
panel_radium.setText("Orbit radium: "+String.format("%.1f", info.orbit_radium)+" Km");
if(panel_mass != null)
panel_mass.setText("Mass: "+String.format("%.1f", info.mass)+" Kg");
if(panel_roll != null)
panel_roll.setText("Rol: "+String.format("%.1f", (180*info.roll/Math.PI))+"º");
if(panel_pitch != null)
panel_pitch.setText("Pitch: "+String.format("%.1f", (180*info.pitch/Math.PI))+"º");
if(panel_yaw != null)
panel_yaw.setText("Yaw: "+String.format("%.1f", (180*info.yaw/Math.PI))+"º");
}
}
});
//Log.d("Sim",System.currentTimeMillis()+": "+"post update gui 1");
}
编辑2:我实际上可以删除runOnUiThread,因为它已经在那个线程,但效果是一样的,这不是问题。
编辑3:我试图评论方法updateHUD()的所有行,只留下这两行:
if(panel_time != null)
panel_time.setText(info.time.replace("T", " "));
效果几乎相同,如果我触摸任何textView,动画会像定期冻结一样进行
编辑4:
我注意到AsyncTask中的进程花费的时间比可用的步骤时间长,所以它从不睡觉。即使模拟步骤长于可用时间,我也建立了10ms的安全保护时间。所以,我每100ms至少有10ms的空闲时间。效果仍然相同。我在25Hz的浏览器和1Hz的单个textview文本更新。如果我禁用textview更新,webgl模型将平滑动画。另一方面,如果我也启用了textview更新,每次更新文本时,都会有一些毫秒的时间来阻止浏览器动画及其对触摸的响应。如果我增加任务优先级,这种效果会变得更糟。我尝试设置一个500毫秒的巨大守卫,但冻结效果仍然出现。我正在使用XWalkView,当UI线程正在执行时,它是否会阻止此视图的交互?
我无法理解为什么4核2 RAMgb设备需要更多时间来计算相同的模拟,而不是Linux或Windows桌面PC。我有25Hz - > 40ms的可用时间,步数大约需要70ms。在PC中,我可以将模拟实时保持在25Hz。与其他操作系统相比,Android背景中是否有这么多狗屎?
答案 0 :(得分:0)
您的代码必须存在其他问题。尝试在这里发布您的AsyncTask。
你也可以尝试一些非常基本的东西,如:
创建一个每25Hz循环的新线程,并使用UI元素的post()方法或Activity的runInUiThread()更新UI。看看UI线程中是否还有任何代码仍然可以运行,这可以在UI线程之外完成。
答案 1 :(得分:0)
我尝试了除了最逻辑的东西之外的所有东西,在没有连接调试器的情况下尝试应用程序。
模拟比PC更慢的原因,以释放UI事件...所有这些都是因为调试器从设备中获取了大量资源。所以,我想从这一点开始,我将不得不在没有调试器的情况下测试应用程序,这就迫使我每次重启电话以避免等待调试器连接&#34;。
感谢所有尝试过的人。
答案 2 :(得分:0)
我可能错了,但我认为你synchronization
simulator.getSimulationResults()
对象的simulator
问题。我看不到getSimulationResults()
类的实现和getSimulationResults()
返回的对象的实现,但我想simulator.getSimulationResults().updateSimulation(...)
每次都返回相同的对象?如果是这样,那么它可能看起来像这样:
SimulationResults
。如果此方法已同步,则此调用将锁定AsyncTaks
线程的updateSimulation(...)
对象。publishProgress()
返回,并且publishProgress()
被调用,但onProgressUpdate(Void... values)
仅在UI线程中安排onProgressUpdate(Void... values)
。onProgressUpdate(Void... values)
。因此,AsyncTaks线程迈出了第一步。synchronized void updateHUD()
和updateHUD()
方法,但SimulationResults
无法执行,因为updateSimulation(...)
对象被AsyncTaks线程锁定在onProgressUpdate(Void... values)
方法中。因此UI线程将控件返回给OS。这可能会发生很多次。因此,只有当UI线程在AsyncTask线程中未调用updateSimulation(...)
方法的时候获得控件时,才能执行public synchronized void update HUD()
方法和UI线程中的所有事件。
您可以通过替换public void update HUD()
上的{{1}}来检查这个想法,然后在TextView中随机写一些内容。
无论如何,在这种情况下使用AsyncTask不是最好的主意。 AsyncTask在TheadPool中执行,但在Android系统中,此池只能由一个线程组成。因此,所有AsyncTask将在一个线程中逐个执行。