Android Java - Using Handlers Inside For Loop - java

I have a for loop which calls a function to download a file.
Each time the function is called the title of the file is displayed in a TextView.
The problem is the files are downloaded but the UI freezes up, and it is only after the files have finished downloading that the UI is updated, and only the last title for the last file is shown.
for(int i=0; i < Titles.size(); i++){
downloading.setText("Downloading: "+Titles.get(i));
if(!Utils.downloadFile(Mp3s.get(i))){
downloading.setText("ERROR Downloading: "+Titles.get(i));
}
}
I know I have to use a Handler or Thread to sort this issue out.
But I am not sure how to implement it.

You could try using Activity.runOnUiThread() - something like:
// Move download logic to separate thread, to avoid freezing UI.
new Thread(new Runnable() {
#Override
public void run() {
for(int i=0; i < Titles.size(); i++) {
// Those need to be final in order to be used inside
// Runnables below.
final String title = Titles.get(i);
// When in need to update UI, wrap it in Runnable and
// pass to runOnUiThread().
runOnUiThread(new Runnable() {
#Override
public void run() {
downloading.setText("Downloading: "+title);
}
});
if(!Utils.downloadFile(Mp3s.get(i))) {
runOnUiThread(new Runnable() {
#Override
public void run() {
downloading.setText("ERROR Downloading: "+title);
}
});
}
}
}).start();
That's pretty verbose (yeah, Java!) and, in my opinion, not very readable.
Another solution would be to use AsyncTask, which has convienient onProgressUpdate() method designed to update UI for a long-running task. It could look like:
public class DownloadTask extends AsyncTask<URL, String, Void> {
// This method will be run off the UI thread, no need to
// create separate thread explicitely.
protected Long doInBackground(URL... titles) {
for(int i=0; i < titles.length; i++) {
publishProgress("Downloading " + titles[i]);
if(!Utils.downloadFile(Mp3s.get(i))) {
publishProgress("ERROR Downloading: " + titles[i]);
}
}
}
// This method will be called on the UI thread, so
// there's no need to call `runOnUiThread()` or use handlers.
protected void onProgressUpdate(String... progress) {
downloading.setText(progress[0]);
}
}
(please note that code above is hand-written not-compiled, so it's probably buggy, but it should give you an idea how to go from here.

Related

update marker position every x time in asynctask

I wanted to mock location of a marker on map. I have list of LatLng values store in ArrayList. I use this value to update on map every second. I need this function to works in AsyncTask so that my UI thread will still responsive.
Initially, I tried using Thread.sleep() but made application not responsive.
protected String doInBackground(Void... voids) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
for (int i = 0; i < waypoint.size(); i++) {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i));
try {
Thread.sleep(1000); // Thread sleep made application not responsive.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, 500);
return null;
}
I also tried using .postDelayed but the integer i needs to get declared final which is a problem because I need the integer to change value.
protected String doInBackground(Void... voids) {
for (int i = 0; i < waypoint.size(); i++) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i)); // Integer i needs to declare final.
}
}, 1000);
}
return null;
}
Is there any way to do this? Thank you.
The Thread.sleep() approach is OK if you can spare a worker thread. The problem in your code is that the thread you are pausing is the UI Thread, that's why your application freezes. You have to understand that what your doing there is just publishing a runnable to the UI Thread using the Handler construct, nothing more.
In your second approach, you can dump the Handler part and use publishProgress (called from the background) after you override onProgressUpdate (delivered in UI thread) in your AsyncTask based class. It does effectively the same but with less boilerplate. Take a look at https://developer.android.com/reference/android/os/AsyncTask for details.
Finally, to circumvent the final requirement in anonymous classes, you can declare a final array of one element and use position 0 to read/write the value. Hopefully, you won't need to do this too often.
The fastest (but not the most correct when working with MultiThreading) way is:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
}, 1000);
}
return null;
}
I don't know what was the Type of "waypoint" List, so I wrote "TYPE_OF_WAYPOINTS" as placeholder.
#emandt answer does not work but the idea he gave could work. So I tried and it is working flawlessly with some modified from his answer:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
});
try {
Thread.sleep(1000);
} catch (Exception e) {
// catch exception here
}
}
return null;
}
Firstly, I have change the .postDelayed to .post. Then, to delay the operation by one second, I have added Thread.sleep(1000) inside for (...) but outside new Handler(Looper.getMainLooper()).post(...));.
Now, the application could do the process in the background with user still be able to interact with the UI. Thanks.

How exactly using the Looper() and Handler()

Can someone help me to correct my code.
(https://i.stack.imgur.com/jKOvH.png)
I am trying to display realtime Count from 0 to 10 and displaying that on textView but always crash. Iam new on android but Very excited to learn.please help me explain that problem. Sorry for my bad English.
Well, i'm not an Android developer myself but from what i understood online, what you did is to create a Handler and provide Looperassociated with the main thread. This associate this handler to the main thread. When we post the Runnable, it gets queued in the main thread’s MessageQueue and then executed in the main thread.
Creating an own thread and providing Lopper and MessageQueue is not the right way to deal with the problem. So, Android has provided HandlerThread(subclass of Thread) to streamline the process. Internally it does the same things that we have done but in a robust way. So, always use HandlerThread.
private class MyHandlerThread extends HandlerThread {
Handler handler;
public MyHandlerThread(String name)
{
super(name);
}
#Override
protected void onLooperPrepared() {
handler = new Handler(getLooper()) {
#Override
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
}
}
Information found at: https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a
Try this code to create new thread under activity. there is no need to create handler.
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
text.setText(value);
}
}
};
new Thread(runnable).start();
just :
new Handler().post(new Runnable() {
#Override
public void run() {
...
}
});
you can try it.

Infinitely Looping A Thread In Android

I'm trying to infinitely loop a thread but it keeps running only once. The only solutions I could find was for older version of Java which appear to not be working anymore.
Here is the Activity that starts the loop:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread growCoin = new Thread(new GrowingCoin());
growCoin.start();
}
}
Class that handles the loop:
public class GrowingCoin implements Runnable{
CoinTracker co = new CoinTracker();
boolean runGrowLoop = true;
public void run(){
try{
while(runGrowLoop == true){
co.copper = (int) (co.copper + (co.copper * 0.2));
MainActivity.coppertv.setText("Copper: " + co.copper);
Thread.sleep(1000);
Log.i("thread debug", "thread sleeping");
}
}
catch(Exception e){
}
}
}
I'm assuming it has something to do with the CoinTracker class not updating because I've had a similar problem before but if that is the case I do not know how to solve the problem.
Thanks in advance for any solutions/attempts at solving.
EDIT:
I have very little experience with LogCat but I assume the tag System.err means something important so here's everything I got from that tag. I cannot figure out what the error message means:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6247)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:902)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:4637)
at android.view.View.invalidateInternal(View.java:11690)
at android.view.View.invalidate(View.java:11654)
at android.view.View.invalidate(View.java:11638)
at android.widget.TextView.checkForRelayout(TextView.java:6842)
at android.widget.TextView.setText(TextView.java:4047)
at android.widget.TextView.setText(TextView.java:3905)
at android.widget.TextView.setText(TextView.java:3880)
at me.test.first.GrowingCoin.run(GrowingCoin.java:13)
at java.lang.Thread.run(Thread.java:818)
Becareful when doing something like while(runGrowLoop == true), it will take a lot of CPU resources. You should use synchronized block.
Take a look here, it already has an answer :
Android infinite loop in thread
Try it with an AsyncTask. And update your View through the OnProgressUpdate Methode.
You can do your stuff in the doInBackground method e.g.
protected Long doInBackground(URL... urls) {
while(runGrowLoop){
// Something to do.
publishProgress(1L)
}
}
You surely got exception at :
MainActivity.coppertv.setText("Copper: " + co.copper);
with some title of:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
so you must do it something like:
MainActivity.coppertv.post(new Runnable() {
#Override
public void run() {
MainActivity.coppertv.setText("Copper: " + co.copper);}
});
or use
runOnUiThread(new Runnable() {
#Override
public void run() {
MainActivity.coppertv.setText("Copper: " + co.copper);}
});
to update the views.

How to wait in loop in Vaadin?

Im trying to display series of photos on one page with time interval. In countinuos while loop i got:
while(true){
if (zmienna == fa.length) zmienna = 0;
Image obrazek = new Image("",pliki[zmienna]);
layout.replaceComponent(staryObrazek, obrazek);
obrazek.requestRepaint();
staryObrazek = obrazek;
zmienna++;
try {
Thread.sleep(2000) ;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It showing only waiting icon, dispaying mwthod works fine without loop. Do anyone has an idea how I should fic this issue?
In all modern UI systems you will have to not suspend the main thread, but use a background thread to update the UI. Otherwise you block the whole UI.
In Vaadin 7 you can enable server push and then use a background thread to change the image every 2 seconds.
Enabling push is described in the book of vaadin https://vaadin.com/de/book/vaadin7/-/page/advanced.push.html
Your code could look like this:
public class PushyUI extends UI {
#Override
protected void init(VaadinRequest request) {
// Set first component/image
setContent(chart);
// Start the update thread
new ImgUpdThread().start();
}
class ImgUpdThread extends Thread {
#Override
public void run()
{
// Update the data for a while
while (count < 100) {
Thread.sleep(1000);
access(new Runnable() {
#Override
public void run() {
//update the UI as in your code above
}
});
}
}
It is important to use the access(...) method to sync access to the UI elements.

JProgressBar will not update until process is completed

Tons of JProgressBar questions on here I know, but through all the answers and I can't seem to diagnose my issue. I am processing a file with some address verification software. I click the Process button and I need my JProgressBar to update with each file processed.
Here is the button:
private JButton getJButton0() {
...
jButton0.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
jButton0ActionActionPerformed(event);
t.start();
}
...
Per everybody's recommendation, I used the setValue() method within a thread
Thread t = new Thread(){
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
...
BulkProcessor.getPercentComplete() is a method I'm calling from another class which represents the percentage complete. I have tested this method and it updates correctly. The issue is that the progress bar will not update until the files are finished processing, and then it will jump to 100%. I apologize if this is a repeat question, but I have done some serious digging on this site with no luck. Any help much appreciated.
Edit:
Per recommended duplicate, I tried this:
public void update(){
new SwingWorker<Void,Void>() {
protected Void doInBackground() throws Exception {
jProgressBar0.setValue(BulkProcessor.getPercentComplete());
return null;
};
}.execute();
}
And then tried calling this update() method under the actionPerformed() (switched t.start() with update()). I am still having the same issue.
Edit
Based on user1676075's recommendation, however same issue:
public static void update(){
new SwingWorker<Void,Integer>() {
protected Void doInBackground() throws Exception {
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentComplete);
Thread.sleep(100);
} while(percentComplete < 100);
return null;
}
#Override
protected
void process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
}
Edit
Here is the code from my BulkProcessor class
private String getOutputLine( String searchString, String inputLine )
throws QasException
{
..(code for processing lines)..
countRecord++;
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
totalRecord is updated in the main class of my BulkProcessor class
public static void main( String input, String output ){
count.clear();
try{
String inputFile = input;
String outputFile = output;
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(input)));
lnr.skip(Long.MAX_VALUE);
totalRecord = lnr.getLineNumber() + 1; //line count in file
BulkProcessor bulk = new BulkProcessor(inputFile, outputFile, ConfigManager.DFLT_NAME);
bulk.process();
}catch(Exception e ){
e.printStackTrace();
}
}
Looks like you're mixing usages. See the SwingWorker documentation, example at the top: http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html.
Ideally you'd update your BulkProcessor in the doInBackground method of the SwingWorker, and that would call setProgress, and the jProgressBar would be listening for those progress updates as in the example.
If that won't work for you, which it seems like it won't just based on the above, start a SwingWorker from the button press event. Implement the SwingWorker methods kinda like this (pseudocode):
new SwingWorker<Void,Integer>()
{
doInBackground()
{
do
{
percentComplete = BulkProcessor.getPercentComplete();
publish(percentCompete);
Thread.sleep(100);
} while (percentComplete < 100);
}
#Override
process(List<Integer> progress)
{
jProgressBar0.setValue(progress.get(0));
}
}.execute();
You'll need to add error-handling and checks for complete and failure cases, but that should get you started and to where you want to be. doInBackground runs in a background thread so won't block anything, and process() runs on the swing worker thread so will post the updates.
The mistake you probably went on is calling the t.start(); after thejButton0ActionPerformed(event); which makes that after the action is performed the thread will start. Therefore the value of the progress bar is not updated as intended.
You need to start the thread in jButton0ActionPerformed(event); and then update the value in it.
Just a hunch, but...
percentComplete = (int) Math.round((countRecord/totalRecord)*100);
Are you sure this is not integer arithmetic? I don't know the type of totalRecord, so I can't say for sure.
I'd guess everything works fine, and just the progress is 0 all the time, until complete where it magically is 100. This is because an int divided by an int will not have fraction values (ie. 99/100 == 0, 100/100 == 1). This fits perfectly with the symptoms you are experiencing.
Try replacing the line above with:
percentComplete = (int) Math.round((countRecord/(double) totalRecord)*100);
to see it I'm right. :-)
Have you tried to use the PropertyChangeListener-interface?
The calculations will be done by the Swingworker-thread and the main-gui will implement this interface. Some example-code
#Override
public void actionPerformed(ActionEvent e) {
this.myButton.setEnabled(false);
MyWorkerThread thread = new MyWorkerThread(); //Data-processing
thread.addPropertyChangeListener(this.mainguiframe); //Separation of concern
thread.execute();
}
Using the "setProgress"-method of the swing-worker-thread the main-gui-thread will be notified if something has happend.
#Override
public void propertyChange(PropertyChangeEvent property) {
Integer currentValue = new Integer(0);
currentValue = (Integer) property.getNewValue();
this.progressBar.setValue(currentValue.intValue());
}
Swing is not thread-safe. This is not the best solution but perhaps it can help you. Please comment if there is somethin horrible wrong.

Categories