Question

I am using an AsynchTask to host a simulator that runs indefinelly and posts the results after each simulation step.

Limiting the simulation loop in background at a maximum of 25Hz, and only calling a javascript function with the results, it works "fine".

Apart from updating a webgl model in a browser, what looks fast enough, I have two more things to update from the Android UI: the FPS indicator and the panel with TextViews representing some of the values. If we forget about the FPS:

The onProgressUpdate() function is already limited to be called at 25Hz, to refresh the model. Now I use another time variable to limit, inside this method, the call to another method that updates the UI panel textViews. It is limited to 1Hz, less than what I actually wanted but fast enough for the kind of information. The method is as clean as possible, all the views are previously loaded to a variable that I keep to not load them every time.

What is the effect: looks like updating 5 textViews takes like one second where all the UI freezes, the touch moves are very very laggy...

I decreased the priority of the background task with:

@Override
protected Boolean doInBackground(ModelSimulation... params) {
    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
...

And used Thread.yield() at the end of the doInBackground method. This improves the behavior to what I explained, without these commands, the behavior is even worst.

My questions are:

-Can I reduce even more the priority if instead of using a background task I use a handler and my own Thread?

-Will a service improve the behavior of the UI?

-Why updating 5 textViews takes so long compared with calling a javascript function that finally will have to use the gpu to change the webgl model?

-Is Android not prepared in any sens to do dynamic applications? How applications like the ones to test sensors update so fast the UI? because there are not standar components like the textViews? (like browser going faster than a textView)

Note: even reducing the refreshing limitations, it produce a laggy effect every time the HUD is updated. In fact I talk about 5 textViews but only updating the FPS indicator produces the same pause. Looks like the only fact of having to switch to the UI thread already consumes this time.

Edit 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();
    }
}

If I comment the line simulator.getSimulationResults().updateHUD(); or directly the contents of the method, it works "fine". And this method is only changing some textviews text:

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");
}

Edit 2: I can actually remove the runOnUiThread since it is already at that thread, but the effect is the same, this is not the problem.

Edit 3: I tried to comment all the lines of the method updateHUD() and leave only these two:

if(panel_time != null)
panel_time.setText(info.time.replace("T", "  "));

The effect is almost the same, if I touch any textView, the animation goes by steps like periodically freezing

Edit 4:

I noticed that the process inside the AsyncTask was taking longer than the available step time so it was never sleeping. I established a safe guard time of 10ms that is slept even if the simulation step is longer than the available time. So, I have minimum 10ms free of each 100ms. The efect stills the same. I am updating at 25Hz the browser and 1Hz a single textview text. If I disable the textview update, the webgl model animates smoothly. On the other hand, if I enable the textview update too, every time the text is updated, there are some miliseconds where the browser animation and its response to touches are blocked. This effect gets worst if I increase the task priority. I tried setting a huge guard of 500ms but the freezing effect stills appearing. I am using XWalkView, can it be something blocking the interaction of this view when UI Thread is acting?

I can't understand why a 4 core 2 RAMgb device needs way more time to compute the same simulation than in Linux or windows desktop PC. I have 25Hz-->40ms of available time and the steps take almost 70ms. In a PC I could keep the simulation at 25Hz in real time. Is there so much shit running in background in Android compared to other OS?

Was it helpful?

Solution 2

I tried literally everything except for the most logic thing, trying the application without the debugger connected.

The reason to have slower simulation than in a PC, to freese UI events... all because the debugger takes a lot of resources from the device. So, I guess that from this point and avobe I will have to test the application without debugger, what forces me to reboot the phone each time to avoid the "waiting for debugger to connect".

Thank to all who tried.

OTHER TIPS

There must be another issue with your code. Try posting your AsyncTask in here.

You could also try something very basic like:

Create a new Thread that loops every 25Hz and update your UI by using the post() method of your UI elements or the runInUiThread() of your Activity. See if there's any code still running inside the UI Thread, that could do heavy work, that can be done outside the UI Thread.

I could be wrong, but I think that yours problem in synchronization on simulator.getSimulationResults() object. I can't see the realization of the simulator class and realization of the object returned by getSimulationResults(), but I suppose that getSimulationResults() returns the same object every time? If so, then it can be looks like this:

  1. In the AsyncTaks call simulator.getSimulationResults().updateSimulation(...). If this method is synchronized, then this call will be lock the SimulationResults object for AsyncTaks thread.
  2. updateSimulation(...) returns, and publishProgress() is called, but publishProgress() is only schedule the onProgressUpdate(Void... values) in the UI thread.
  3. The new iteration in the AsyncTaks thread can be started befor the UI thread gets the control and executes onProgressUpdate(Void... values). So, AsyncTaks thread goes to the first step.
  4. The UI thread gets the control and executes the onProgressUpdate(Void... values) and synchronized void updateHUD() methods, but updateHUD() can't be executed, because SimulationResults object is locked by the AsyncTaks thread in the updateSimulation(...) method. So the UI thread returns the control to the OS. This may occur many times.

So, onProgressUpdate(Void... values) method and all events in the UI thread can be executed only if the UI thread gets the control in the right moment when updateSimulation(...) method is not called in the AsyncTask thread.

You can check this idea by replacing the public synchronized void update HUD() on the public void update HUD(), and write something randomly in the TextView.


In any case, the use of AsyncTask in this case is not the best idea. AsyncTask's are executed in the TheadPool, but in the Android system this pool can consist from only one thread. So, all AsyncTask's will be executed one by one in the one thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top