android while loop alternative - android

This is my first Android application and I am finding troubles with while loop, I am trying to use a while loop on my Android application but the application freezes.
What I'm trying to do is track the user location (using onlocationChanged) and keep querying on the location until the query returns a result. It's a GIS application so I am going to describe the application behavior:
the application keeps tracking the user position using a listener "onLocationChangedListener" and store it in a variable "myPosition". I am using a boolean"noResults=true". I will use a method "query(myPosition)" in the while loop, this method has a callback that when a result is found, and changes a boolean "noResults" to false. the loop will keep on until "noResults" is false (that means query's callback changed the boolean's value)
, here's what I did:
while(noResults)
{
//myPosition keeps changing
query(myPosition);
//query has a callback that when a result is found it changes noResults to false
}

I resolved the problem using a "Handler" that query the Feature Layer every 5 seconds, this stops the main thread from generating application not responding error:
Handler m_handler=new Handler();
Runnable m_runnable;
m_runnable = new Runnable(){
public void run() {
//query code here
m_handler.postDelayed(m_runnable, 5000);
}
};
m_handler.postDelayed(m_runnable, 0);

running while loop codes on the main thread freezes the UI, and makes all other processes pause making your app unresponsive use
Threads..
also note that the while loop you are running is running on a default Thread termed as the ui thread so in short run while loops on separate threads..
eg..
new Thread(new Runnable() {
#Override
public void run() {
// Your hard while loop here
//get whatever you want and update your ui with ui communication methods.
}
).start();
for ui communicating methods
View.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getActivity(), "updated ui", Toast.LENGTH_LONG).show();
}
});
the view could be any views you are updating..
also like #TehCoder said you could use asynctask but asynctask is not meant for long workaflow work there are 3 of them but i can't recall the last one

Maybe you should use an AsyncTask? I'm not quite sure what your problem is tho.

Loop is not a problem in android (or any language).
There are two scenario might be reason for your freezing,
If you run network call in api, android throw error and crashes. You have to do network related calls in Aysnc Task ot threading
Use try throw catch and exception cases to avoid app crashing and better coding skill.

Related

Android sequential execution of functions

I know Android UI is not really meant for executing functions and waiting for them to finish, however, I think there are use cases were it is required, like networking.
My problem is, I want to run a series of network operations that rely on each other and take a bit more time than the split second it takes to the next execution, so some waiting is in order:
Start hotspot
Get network interfaces and IP
Start socket
Initially I tested that all is working using buttons, then it waited between my button presses. But now I'd like to automatize it. I googled but all I found are solutions with Async task, which is deprecated. I tried with threads and join, but that usually causes weird crashes in the runnable, and it is not very elegant. I wonder if there is another solution?
The best thing you can do with SDK it's use Executors to run your work in background sequentially
val newSingleThreadExecutor = Executors.newSingleThreadExecutor()
newSingleThreadExecutor.execute {
// 1...
}
newSingleThreadExecutor.execute {
// 2...
}
But if you want to touch the UI from background should create handler check if view's not null
val handler = Handler(Looper.myLooper()!!)
newSingleThreadExecutor.execute {
handler.post {
view?.visibility = View.GONE
}
}
How about something like this?
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startHotspot();
getNetworkInterfaceAndIP();
startSocket();
}
}, 300);

Toast inside thread during heavy workload task

I am updating a database (SQLite) with a lot of data, which takes several minutes. I am doing this on a Thread. At the same time I want to show the progression of the updates (25%, 50%, etc.) through a Toast. Since I am within a thread, I need to use the runOnUiThread() function to run the Toast. Like this:
getActivity().runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getActivity(),"Updating the database...", Toast.LENGTH_SHORT).show();
}
});
It was working fine when the workload was not to big. Now that it is, no toast is being displayed at all.
I have been looking for ways to set a very high priority to the toast's thread, without success. Maybe I can bypass using a thread for the toast in the first place?
Thank you for the insights!
EDIT: In fact, the toast is working, but is displayed after all the work has been done. I want to notify the percentage of the complete update to the user, so I need to have the toast displayed during the update and not after.
I tried removing the workload (no database update, only a Log.d inside the for loop of things to add to the database). And the toast are displayed after the loop is finished although the runOnUiThread() method is called inside the loop.
EDIT 2: I managed to do what I wanted after cleaning up the code and starting fresh. I posted the code I used as the answer below.
After having cleaned up the initial thread, I managed to have something working. I post the code here since it can be used as a template to do a specific task:
Run a initial thread that does tasks periodically for a given number of times (here collect some data). After this given number of times, the collected data is pushed to a database and the user is notified of the advancement of the process (which takes a long time).
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
long t0 = System.currentTimeMillis();
#Override
public void run() {
if(System.currentTimeMillis() - t0 > EXPERIMENT_DURATION ){
processData(dataArrayList); // custom tasks - see below
cancel();
}else {
dataArrayList = collectData(); // custom tasks
}
}
}, 0, INTERVAL);
With:
void processData(Arraylist<Data> dataArrayList){
for(Data data : dataArrayList){
// show progression to the user
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
int percent = Math.round(((float)dataArrayList.indexOf(data))/((float)dataArrayList.size())*100)
Toast.makeText(getActivity(),"Update: " + Integer.toString(percent) + "%", Toast.LENGTH_LONG).show();
}
});
updateDataBase(data);
}
}
I highly recommend you use an AsyncTask.
AsyncTask performs in another working Thread, but it offers a method that is executed in the UI Thread, publishProgress(String ...). that you then customize by overwriting onProgressUpdate(String ...).
EDIT: As read in the comments, AsyncTask is not that good of an option because:
All AsyncTask share a Thread (they don't run on workers as I expected)
For long running Tasks, all other AsyncTasks (system's and your's) will be on hold
This includes AsyncTasks from libraries

How to get user feedback (e.g. from AlertDialog) inside AsyncTask/Background-Thread?

an Android 4+ app should perform a long running operation. This could be copying a million files from A to B for example. To not block the UI this operation runs in the background using an AsyncTask.
Assume that the operation needs some user feedback in the middle of the process to continue its work, e.g. "File XY already exists. Override, Irgnore or Rename?"
What is the best way to get this feedback from the user? Since the operation is running in a background thread one could not just present an AlertDialog (or something similar) since UI interaction is only possible in the main thread...
So for I came across these solution:
Ask for feeback before background threads starts, e.g. ask how to handle conflicts before starting to copy/move the files in the
background.
Do not handle conflicts but note them to ask the user
how to handle them after the operation is complete in a new
operation.
End the background operation on the first conflict, ask the user for feedback and continue a new background operation
I do not like any of these solutions. In the first case the user is asked for feedback even if there will be no conflict at all. The second solutions is not possible if the steps have to be processed in a specific order. The third solution would result in code that is very difficult to read/understand/maintain.
A good solution would be:
Stop the background thread
Marshal to the UI thread and get feedback from the user
Resume background thread and use feedback to continue the operation
Using GCD in Objectiv-C/iOS or async/await in C# this is not a big problem. But how can this be done in Android using AsyncTask?
Meanwhile I thought, that I found an answer here: Simply run myActivity.runOnUiThread(...) within doInBackground(...) and wait for it. Sounds good, but it does not work. The AsyncTask/background thread does NOT wait for the Runnable to finish:
private void copyFiles() {
CopyTask copyTask = new CopyTask (this);
copyTask.execute();
}
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
#Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
I would expect, that when a conflict is detected the Runnable is executed and and Pos 1 (code inside Runnable to resolve conflict) is executed BEVOR Pos 2 is reached. This is not the case. The Runnable is executed correctly but the AsyncTask does not wait for it to finish. The execution of doInBackground is continued without any interruption. It seems that doInBackground and the Runnable are executed in parallel (not suprising since they are executed on different threads) but why does doInBackground not wait?

Android dynamic UI update from AsynchTask/Handler and Thread priorities

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?
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 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.
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:
In the AsyncTaks call simulator.getSimulationResults().updateSimulation(...). If this method is synchronized, then this call will be lock the SimulationResults object for AsyncTaks thread.
updateSimulation(...) returns, and publishProgress() is called, but publishProgress() is only schedule the onProgressUpdate(Void... values) in the UI thread.
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.
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.

How can I keep UI elements responsive while my program is working?

The UI I am creating includes a button, which once pressed, is supposed to find and display values repetitively until the user presses the button again.
This is my button's initialization with the listener:
pollOn = false;
pollButton = (Button) findViewById( R.id.pollButton );
pollButton.setOnClickListener( new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i( "POLL BUTTON", "onClick" );
if( !pollOn ) {
Log.i( "POLL BUTTON", "!pollOn" );
pollOn = true;
methodToReadAndDisplayData();
} else {
Log.i( "POLL BUTTON", "else pollOn" );
pollOn = false;
}
}
});
It is not shown here to make things easier to read, but the way I currently have it working is to call the methodToReadAndDisplayData() 5 times in a for loop and then stop.
So when I press the pollButton initially, the UI freezes and Log.i("POLL BUTTON", "onClick") is displayed at the top of LogCat. I then press the pollButton while it appears to be frozen, and after all of the work is done and the UI unfreezes, Log.i("POLL BUTTON", "onClick") is shown at the very end of my LogCat. The way I am interpretting this is that the button click is entered into a queue, and the onClick method is called after all 5 iterations of the for loop have been completed.
Another large part of this problem is that the work being done is mainly in a native library, and is called using the NDK. I am unsure if this has anything to do with the UI freezing, but it definitely increases the processing time needed.
If anything is unclear or confusing please let me know and I will try to clarify things.
Any information on this situation would be greatly appreciated.
Doing some stuff while keeping the UI responsive can achieved by many methods, two of them are very common. Async Task and threads.
AsyncTask:
It's a class which have a few methods which help you to do time consuming work while updating the UI at the same time. For Example: If you want to search a specific word in a big document, do the reading and searching stuff in doInBackground() (a method of AsyncTask class) and you can display a progress bar and notify the user with your progress with onProgressUpdate(). This gives your app more professional feel and at the same time helps you executing time consuming task in background.
Threads:
They are simple runnable threads. You can execute non UI stuff with these threads but you can't perform UI tasks in them (as UI is not thread safe). For dealing with UI in these threads, you will have to use Handlers, which is quite cumbersome for beginners to get a grip and understanding of them.
So depending on your needs and app you can choose the one best suits you.
Because you're running on the main thread the system UI freezes, you'd be better off running in a new thread which would leave your UI running as normal. Below is an example of how to run your method in a new thread.
new Thread(new Runnable() {
#Override
public void run() {
methodToReadAndDisplayData();
}
}).start();
Note that if your method interacts with the UI in any way, you need to do it via the following:
When you want to update your UI:
Handler threadHandler = new Handler();
threadHandler.post(updateRunnable);
Update your UI here:
Runnable updateRunnable = new Runnable() {
public void run() {
example.setText(newValue);
}
};
Try that and see if there's any improvement. I've not worked with the NDK, just the standard SDK so there may be difference I'm unaware of.
Do it on another thread. Use an AsyncTask to call methodToReadAndDisplayData.

Categories

Resources